PostgreSQL Source Code  git master
multixact.c File Reference
#include "postgres.h"
#include "access/multixact.h"
#include "access/slru.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "access/xact.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "funcapi.h"
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "postmaster/autovacuum.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/builtins.h"
#include "utils/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 isLockOnly)
 
char * mxid_to_string (MultiXactId multi, int nmembers, MultiXactMember *members)
 
void AtEOXact_MultiXact (void)
 
void AtPrepare_MultiXact (void)
 
void PostPrepare_MultiXact (TransactionId xid)
 
void multixact_twophase_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postcommit (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postabort (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
Size MultiXactShmemSize (void)
 
void MultiXactShmemInit (void)
 
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 dclist_head MXactCache = DCLIST_STATIC_INIT(MXactCache)
 
static MemoryContext MXactContext = NULL
 

Macro Definition Documentation

◆ debug_elog2

#define debug_elog2 (   a,
  b 
)

Definition at line 334 of file multixact.c.

◆ debug_elog3

#define debug_elog3 (   a,
  b,
  c 
)

Definition at line 335 of file multixact.c.

◆ debug_elog4

#define debug_elog4 (   a,
  b,
  c,
 
)

Definition at line 336 of file multixact.c.

◆ debug_elog5

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

Definition at line 337 of file multixact.c.

◆ debug_elog6

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

Definition at line 338 of file multixact.c.

◆ MAX_CACHE_ENTRIES

#define MAX_CACHE_ENTRIES   256

Definition at line 323 of file multixact.c.

◆ MAX_MEMBERS_IN_LAST_MEMBERS_PAGE

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

Definition at line 155 of file multixact.c.

◆ MaxOldestSlot

#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)

Definition at line 290 of file multixact.c.

◆ MULTIXACT_FLAGBYTES_PER_GROUP

#define MULTIXACT_FLAGBYTES_PER_GROUP   4

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

◆ MULTIXACT_MEMBER_SAFE_THRESHOLD

#define MULTIXACT_MEMBER_SAFE_THRESHOLD   (MaxMultiXactOffset / 2)

Definition at line 177 of file multixact.c.

◆ 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

#define MULTIXACT_MEMBERS_PER_PAGE    (MULTIXACT_MEMBERGROUPS_PER_PAGE * MULTIXACT_MEMBERS_PER_MEMBERGROUP)

Definition at line 142 of file multixact.c.

◆ MULTIXACT_OFFSETS_PER_PAGE

#define MULTIXACT_OFFSETS_PER_PAGE   (BLCKSZ / sizeof(MultiXactOffset))

Definition at line 109 of file multixact.c.

◆ MultiXactIdToOffsetEntry

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

Definition at line 113 of file multixact.c.

◆ MultiXactIdToOffsetPage

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

Definition at line 111 of file multixact.c.

◆ MultiXactIdToOffsetSegment

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

Definition at line 115 of file multixact.c.

◆ MultiXactMemberCtl

#define MultiXactMemberCtl   (&MultiXactMemberCtlData)

Definition at line 191 of file multixact.c.

◆ MultiXactOffsetCtl

#define MultiXactOffsetCtl   (&MultiXactOffsetCtlData)

Definition at line 190 of file multixact.c.

◆ MXACT_MEMBER_BITS_PER_XACT

#define MXACT_MEMBER_BITS_PER_XACT   8

Definition at line 130 of file multixact.c.

◆ 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.

◆ MXOffsetToFlagsBitShift

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

Definition at line 167 of file multixact.c.

◆ MXOffsetToFlagsOffset

#define MXOffsetToFlagsOffset (   xid)
Value:

Definition at line 163 of file multixact.c.

◆ MXOffsetToMemberOffset

#define MXOffsetToMemberOffset (   xid)
Value:
#define MULTIXACT_FLAGBYTES_PER_GROUP
Definition: multixact.c:135
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:163

Definition at line 172 of file multixact.c.

◆ MXOffsetToMemberPage

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

Definition at line 159 of file multixact.c.

◆ MXOffsetToMemberSegment

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

Definition at line 160 of file multixact.c.

◆ OFFSET_WARN_SEGMENTS

#define OFFSET_WARN_SEGMENTS   20

◆ PreviousMultiXactId

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

Definition at line 181 of file multixact.c.

◆ SHARED_MULTIXACT_STATE_SIZE

#define SHARED_MULTIXACT_STATE_SIZE
Value:
add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
TransactionId MultiXactId
Definition: c.h:651
#define MaxOldestSlot
Definition: multixact.c:290
Size add_size(Size s1, Size s2)
Definition: shmem.c:502
Size mul_size(Size s1, Size s2)
Definition: shmem.c:519

Typedef Documentation

◆ MultiXactStateData

◆ mXactCacheEnt

typedef struct mXactCacheEnt mXactCacheEnt

◆ mxtruncinfo

typedef struct mxtruncinfo mxtruncinfo

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1688 of file multixact.c.

1689 {
1690  /*
1691  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1692  * which should only be valid while within a transaction.
1693  *
1694  * We assume that storing a MultiXactId is atomic and so we need not take
1695  * MultiXactGenLock to do this.
1696  */
1699 
1700  /*
1701  * Discard the local MultiXactId cache. Since MXactContext was created as
1702  * a child of TopTransactionContext, we needn't delete it explicitly.
1703  */
1704  MXactContext = NULL;
1706 }
BackendId MyBackendId
Definition: globals.c:85
static void dclist_init(dclist_head *head)
Definition: ilist.h:671
static MemoryContext MXactContext
Definition: multixact.c:325
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:295
static dclist_head MXactCache
Definition: multixact.c:324
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:294
#define InvalidMultiXactId
Definition: multixact.h:24

References dclist_init(), InvalidMultiXactId, MXactCache, MXactContext, MyBackendId, OldestMemberMXactId, and OldestVisibleMXactId.

Referenced by AbortTransaction(), and CommitTransaction().

◆ AtPrepare_MultiXact()

void AtPrepare_MultiXact ( void  )

Definition at line 1716 of file multixact.c.

1717 {
1718  MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId];
1719 
1720  if (MultiXactIdIsValid(myOldestMember))
1722  &myOldestMember, sizeof(MultiXactId));
1723 }
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1258
#define TWOPHASE_RM_MULTIXACT_ID
Definition: twophase_rmgr.h:27

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

Referenced by PrepareTransaction().

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 1894 of file multixact.c.

1895 {
1896  int slotno;
1897 
1898  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
1899 
1900  /* Create and zero the first page of the offsets log */
1901  slotno = ZeroMultiXactOffsetPage(0, false);
1902 
1903  /* Make sure it's written out */
1905  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1906 
1907  LWLockRelease(MultiXactOffsetSLRULock);
1908 
1909  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
1910 
1911  /* Create and zero the first page of the members log */
1912  slotno = ZeroMultiXactMemberPage(0, false);
1913 
1914  /* Make sure it's written out */
1916  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
1917 
1918  LWLockRelease(MultiXactMemberSLRULock);
1919 }
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1195
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1808
@ LW_EXCLUSIVE
Definition: lwlock.h:116
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1947
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1931
#define MultiXactMemberCtl
Definition: multixact.c:191
#define MultiXactOffsetCtl
Definition: multixact.c:190
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:615

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

Referenced by BootStrapXLOG().

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2155 of file multixact.c.

2156 {
2157  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2158 
2159  /*
2160  * Write dirty MultiXact pages to disk. This may result in sync requests
2161  * queued for later handling by ProcessSyncRequests(), as part of the
2162  * checkpoint.
2163  */
2166 
2167  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2168 }
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1157

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ ExtendMultiXactMember()

static void ExtendMultiXactMember ( MultiXactOffset  offset,
int  nmembers 
)
static

Definition at line 2434 of file multixact.c.

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

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

◆ ExtendMultiXactOffset()

static void ExtendMultiXactOffset ( MultiXactId  multi)
static

Definition at line 2404 of file multixact.c.

2405 {
2406  int pageno;
2407 
2408  /*
2409  * No work except at first MultiXactId of a page. But beware: just after
2410  * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2411  */
2412  if (MultiXactIdToOffsetEntry(multi) != 0 &&
2413  multi != FirstMultiXactId)
2414  return;
2415 
2416  pageno = MultiXactIdToOffsetPage(multi);
2417 
2418  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
2419 
2420  /* Zero the page and make an XLOG entry about it */
2421  ZeroMultiXactOffsetPage(pageno, true);
2422 
2423  LWLockRelease(MultiXactOffsetSLRULock);
2424 }
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
#define FirstMultiXactId
Definition: multixact.h:25

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

Referenced by GetNewMultiXactId().

◆ find_multixact_start()

static bool find_multixact_start ( MultiXactId  multi,
MultiXactOffset result 
)
static

Definition at line 2735 of file multixact.c.

2736 {
2737  MultiXactOffset offset;
2738  int pageno;
2739  int entryno;
2740  int slotno;
2741  MultiXactOffset *offptr;
2742 
2744 
2745  pageno = MultiXactIdToOffsetPage(multi);
2746  entryno = MultiXactIdToOffsetEntry(multi);
2747 
2748  /*
2749  * Write out dirty data, so PhysicalPageExists can work correctly.
2750  */
2753 
2755  return false;
2756 
2757  /* lock is acquired by SimpleLruReadPage_ReadOnly */
2758  slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
2759  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2760  offptr += entryno;
2761  offset = *offptr;
2762  LWLockRelease(MultiXactOffsetSLRULock);
2763 
2764  *result = offset;
2765  return true;
2766 }
uint32 MultiXactOffset
Definition: c.h:653
static MultiXactStateData * MultiXactState
Definition: multixact.c:293
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:496
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno)
Definition: slru.c:627

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

Referenced by SetOffsetVacuumLimit(), and TruncateMultiXact().

◆ GetMultiXactIdMembers()

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

Definition at line 1225 of file multixact.c.

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

References Assert(), CHECK_FOR_INTERRUPTS, DEBUG2, debug_elog2, debug_elog3, ereport, errcode(), errmsg(), ERROR, FirstMultiXactId, i, if(), LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactIdSetOldestVisible(), MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactState, MXACT_MEMBER_XACT_BITMASK, mXactCacheGetById(), mXactCachePut(), mxid_to_string(), MXOffsetToFlagsBitShift, MXOffsetToFlagsOffset, MXOffsetToMemberOffset, MXOffsetToMemberPage, 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_should_freeze(), MultiXactIdExpand(), MultiXactIdGetUpdateXid(), MultiXactIdIsRunning(), pg_get_multixact_members(), and pgrowlocks().

◆ GetNewMultiXactId()

static MultiXactId GetNewMultiXactId ( int  nmembers,
MultiXactOffset offset 
)
static

Definition at line 958 of file multixact.c.

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

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

Referenced by MultiXactIdCreateFromMembers().

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2507 of file multixact.c.

2508 {
2509  MultiXactId oldestMXact;
2510  MultiXactId nextMXact;
2511  int i;
2512 
2513  /*
2514  * This is the oldest valid value among all the OldestMemberMXactId[] and
2515  * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2516  */
2517  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2518 
2519  /*
2520  * We have to beware of the possibility that nextMXact is in the
2521  * wrapped-around state. We don't fix the counter itself here, but we
2522  * must be sure to use a valid value in our calculation.
2523  */
2524  nextMXact = MultiXactState->nextMXact;
2525  if (nextMXact < FirstMultiXactId)
2526  nextMXact = FirstMultiXactId;
2527 
2528  oldestMXact = nextMXact;
2529  for (i = 1; i <= MaxOldestSlot; i++)
2530  {
2531  MultiXactId thisoldest;
2532 
2533  thisoldest = OldestMemberMXactId[i];
2534  if (MultiXactIdIsValid(thisoldest) &&
2535  MultiXactIdPrecedes(thisoldest, oldestMXact))
2536  oldestMXact = thisoldest;
2537  thisoldest = OldestVisibleMXactId[i];
2538  if (MultiXactIdIsValid(thisoldest) &&
2539  MultiXactIdPrecedes(thisoldest, oldestMXact))
2540  oldestMXact = thisoldest;
2541  }
2542 
2543  LWLockRelease(MultiXactGenLock);
2544 
2545  return oldestMXact;
2546 }

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

Referenced by heapam_relation_set_new_filelocator(), vac_update_datfrozenxid(), and vacuum_get_cutoffs().

◆ MaybeExtendOffsetSlru()

static void MaybeExtendOffsetSlru ( void  )
static

Definition at line 1975 of file multixact.c.

1976 {
1977  int pageno;
1978 
1980 
1981  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
1982 
1984  {
1985  int slotno;
1986 
1987  /*
1988  * Fortunately for us, SimpleLruWritePage is already prepared to deal
1989  * with creating a new segment file even if the page we're writing is
1990  * not the first in it, so this is enough.
1991  */
1992  slotno = ZeroMultiXactOffsetPage(pageno, false);
1994  }
1995 
1996  LWLockRelease(MultiXactOffsetSLRULock);
1997 }

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

Referenced by MultiXactSetNextMXact().

◆ multixact_redo()

void multixact_redo ( XLogReaderState record)

Definition at line 3233 of file multixact.c.

3234 {
3235  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3236 
3237  /* Backup blocks are not used in multixact records */
3238  Assert(!XLogRecHasAnyBlockRefs(record));
3239 
3240  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3241  {
3242  int pageno;
3243  int slotno;
3244 
3245  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3246 
3247  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
3248 
3249  slotno = ZeroMultiXactOffsetPage(pageno, false);
3251  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3252 
3253  LWLockRelease(MultiXactOffsetSLRULock);
3254  }
3255  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3256  {
3257  int pageno;
3258  int slotno;
3259 
3260  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3261 
3262  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
3263 
3264  slotno = ZeroMultiXactMemberPage(pageno, false);
3266  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3267 
3268  LWLockRelease(MultiXactMemberSLRULock);
3269  }
3270  else if (info == XLOG_MULTIXACT_CREATE_ID)
3271  {
3272  xl_multixact_create *xlrec =
3273  (xl_multixact_create *) XLogRecGetData(record);
3274  TransactionId max_xid;
3275  int i;
3276 
3277  /* Store the data back into the SLRU files */
3278  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3279  xlrec->members);
3280 
3281  /* Make sure nextMXact/nextOffset are beyond what this record has */
3282  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3283  xlrec->moff + xlrec->nmembers);
3284 
3285  /*
3286  * Make sure nextXid is beyond any XID mentioned in the record. This
3287  * should be unnecessary, since any XID found here ought to have other
3288  * evidence in the XLOG, but let's be safe.
3289  */
3290  max_xid = XLogRecGetXid(record);
3291  for (i = 0; i < xlrec->nmembers; i++)
3292  {
3293  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3294  max_xid = xlrec->members[i].xid;
3295  }
3296 
3298  }
3299  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3300  {
3301  xl_multixact_truncate xlrec;
3302  int pageno;
3303 
3304  memcpy(&xlrec, XLogRecGetData(record),
3306 
3307  elog(DEBUG1, "replaying multixact truncation: "
3308  "offsets [%u, %u), offsets segments [%x, %x), "
3309  "members [%u, %u), members segments [%x, %x)",
3310  xlrec.startTruncOff, xlrec.endTruncOff,
3313  xlrec.startTruncMemb, xlrec.endTruncMemb,
3316 
3317  /* should not be required, but more than cheap enough */
3318  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3319 
3320  /*
3321  * Advance the horizon values, so they're current at the end of
3322  * recovery.
3323  */
3324  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3325 
3327 
3328  /*
3329  * During XLOG replay, latest_page_number isn't necessarily set up
3330  * yet; insert a suitable value to bypass the sanity test in
3331  * SimpleLruTruncate.
3332  */
3333  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3334  MultiXactOffsetCtl->shared->latest_page_number = pageno;
3336 
3337  LWLockRelease(MultiXactTruncationLock);
3338  }
3339  else
3340  elog(PANIC, "multixact_redo: unknown op code %u", info);
3341 }
unsigned char uint8
Definition: c.h:493
#define PANIC
Definition: elog.h:42
#define DEBUG1
Definition: elog.h:30
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:2916
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2888
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2213
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:864
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:160
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2362
#define MultiXactIdToOffsetSegment(xid)
Definition: multixact.c:115
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:73
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:72
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:75
#define SizeOfMultiXactTruncate
Definition: multixact.h:100
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:74
MultiXactId mid
Definition: multixact.h:79
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.h:82
MultiXactOffset moff
Definition: multixact.h:80
MultiXactId endTruncOff
Definition: multixact.h:93
MultiXactOffset startTruncMemb
Definition: multixact.h:96
MultiXactOffset endTruncMemb
Definition: multixact.h:97
MultiXactId startTruncOff
Definition: multixact.h:92
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:280
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition: varsup.c:277
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:410
#define XLogRecGetData(decoder)
Definition: xlogreader.h:415
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:412
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:417
#define XLR_INFO_MASK
Definition: xlogrecord.h:62

References AdvanceNextFullTransactionIdPastXid(), Assert(), DEBUG1, elog(), xl_multixact_truncate::endTruncMemb, xl_multixact_truncate::endTruncOff, i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), xl_multixact_create::members, xl_multixact_create::mid, xl_multixact_create::moff, MultiXactAdvanceNextMXact(), MultiXactIdToOffsetPage, MultiXactIdToOffsetSegment, MultiXactMemberCtl, MultiXactOffsetCtl, MXOffsetToMemberSegment, xl_multixact_create::nmembers, xl_multixact_truncate::oldestMultiDB, PANIC, PerformMembersTruncation(), PerformOffsetsTruncation(), 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().

◆ multixact_twophase_postabort()

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

Definition at line 1815 of file multixact.c.

1817 {
1818  multixact_twophase_postcommit(xid, info, recdata, len);
1819 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1800
const void size_t len

References len, and multixact_twophase_postcommit().

◆ multixact_twophase_postcommit()

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

Definition at line 1800 of file multixact.c.

1802 {
1803  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, true);
1804 
1805  Assert(len == sizeof(MultiXactId));
1806 
1807  OldestMemberMXactId[dummyBackendId] = InvalidMultiXactId;
1808 }
int BackendId
Definition: backendid.h:21
BackendId TwoPhaseGetDummyBackendId(TransactionId xid, bool lock_held)
Definition: twophase.c:919

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

Referenced by multixact_twophase_postabort().

◆ multixact_twophase_recover()

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

Definition at line 1779 of file multixact.c.

1781 {
1782  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, false);
1783  MultiXactId oldestMember;
1784 
1785  /*
1786  * Get the oldest member XID from the state file record, and set it in the
1787  * OldestMemberMXactId slot reserved for this prepared transaction.
1788  */
1789  Assert(len == sizeof(MultiXactId));
1790  oldestMember = *((MultiXactId *) recdata);
1791 
1792  OldestMemberMXactId[dummyBackendId] = oldestMember;
1793 }

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2362 of file multixact.c.

2364 {
2365  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2367  {
2368  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2369  MultiXactState->nextMXact = minMulti;
2370  }
2371  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2372  {
2373  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2374  minMultiOffset);
2375  MultiXactState->nextOffset = minMultiOffset;
2376  }
2377  LWLockRelease(MultiXactGenLock);
2378 }
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3182

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

Referenced by multixact_redo(), and xlog_redo().

◆ MultiXactAdvanceOldest()

void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2387 of file multixact.c.

2388 {
2389  Assert(InRecovery);
2390 
2392  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2393 }
bool InRecovery
Definition: xlogutils.c:53

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

Referenced by xlog_redo().

◆ MultiXactGetCheckptMulti()

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

Definition at line 2133 of file multixact.c.

2138 {
2139  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2140  *nextMulti = MultiXactState->nextMXact;
2141  *nextMultiOffset = MultiXactState->nextOffset;
2142  *oldestMulti = MultiXactState->oldestMultiXactId;
2143  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2144  LWLockRelease(MultiXactGenLock);
2145 
2147  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2148  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2149 }
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:338

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

Referenced by CreateCheckPoint().

◆ MultiXactIdCreate()

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

Definition at line 387 of file multixact.c.

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

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

Referenced by compute_new_xmax_infomask().

◆ MultiXactIdCreateFromMembers()

MultiXactId MultiXactIdCreateFromMembers ( int  nmembers,
MultiXactMember members 
)

Definition at line 768 of file multixact.c.

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

References DEBUG2, debug_elog2, debug_elog3, elog(), END_CRIT_SECTION, ERROR, GetNewMultiXactId(), i, InvalidMultiXactId, ISUPDATE_from_mxstatus, xl_multixact_create::mid, xl_multixact_create::moff, MultiXactIdIsValid, mXactCacheGetBySet(), mXactCachePut(), mxid_to_string(), xl_multixact_create::nmembers, RecordNewMultiXact(), SizeOfMultiXactCreate, XLOG_MULTIXACT_CREATE_ID, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

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

◆ MultiXactIdExpand()

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

Definition at line 440 of file multixact.c.

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

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

Referenced by compute_new_xmax_infomask().

◆ MultiXactIdIsRunning()

bool MultiXactIdIsRunning ( MultiXactId  multi,
bool  isLockOnly 
)

Definition at line 552 of file multixact.c.

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

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

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

◆ MultiXactIdPrecedes()

◆ MultiXactIdPrecedesOrEquals()

bool MultiXactIdPrecedesOrEquals ( MultiXactId  multi1,
MultiXactId  multi2 
)

Definition at line 3170 of file multixact.c.

3171 {
3172  int32 diff = (int32) (multi1 - multi2);
3173 
3174  return (diff <= 0);
3175 }

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

◆ MultiXactIdSetOldestMember()

void MultiXactIdSetOldestMember ( void  )

Definition at line 626 of file multixact.c.

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

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

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

◆ MultiXactIdSetOldestVisible()

static void MultiXactIdSetOldestVisible ( void  )
static

Definition at line 683 of file multixact.c.

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

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

Referenced by GetMultiXactIdMembers().

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2825 of file multixact.c.

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

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

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

◆ MultiXactMemberPagePrecedes()

static bool MultiXactMemberPagePrecedes ( int  page1,
int  page2 
)
static

Definition at line 3136 of file multixact.c.

3137 {
3138  MultiXactOffset offset1;
3139  MultiXactOffset offset2;
3140 
3141  offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;
3142  offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;
3143 
3144  return (MultiXactOffsetPrecedes(offset1, offset2) &&
3145  MultiXactOffsetPrecedes(offset1,
3146  offset2 + MULTIXACT_MEMBERS_PER_PAGE - 1));
3147 }

References MULTIXACT_MEMBERS_PER_PAGE, and MultiXactOffsetPrecedes().

Referenced by MultiXactShmemInit().

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3418 of file multixact.c.

3419 {
3420  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3421 }
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition: slru.c:1594

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ MultiXactOffsetPagePrecedes()

static bool MultiXactOffsetPagePrecedes ( int  page1,
int  page2 
)
static

Definition at line 3116 of file multixact.c.

3117 {
3118  MultiXactId multi1;
3119  MultiXactId multi2;
3120 
3121  multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
3122  multi1 += FirstMultiXactId + 1;
3123  multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
3124  multi2 += FirstMultiXactId + 1;
3125 
3126  return (MultiXactIdPrecedes(multi1, multi2) &&
3127  MultiXactIdPrecedes(multi1,
3128  multi2 + MULTIXACT_OFFSETS_PER_PAGE - 1));
3129 }
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109

References FirstMultiXactId, MULTIXACT_OFFSETS_PER_PAGE, and MultiXactIdPrecedes().

Referenced by MultiXactShmemInit().

◆ MultiXactOffsetPrecedes()

static bool MultiXactOffsetPrecedes ( MultiXactOffset  offset1,
MultiXactOffset  offset2 
)
static

Definition at line 3182 of file multixact.c.

3183 {
3184  int32 diff = (int32) (offset1 - offset2);
3185 
3186  return (diff < 0);
3187 }

Referenced by MultiXactAdvanceNextMXact(), and MultiXactMemberPagePrecedes().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3409 of file multixact.c.

3410 {
3411  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3412 }

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactOffsetWouldWrap()

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

Definition at line 2687 of file multixact.c.

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

Referenced by GetNewMultiXactId().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2179 of file multixact.c.

2181 {
2182  debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u",
2183  nextMulti, nextMultiOffset);
2184  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2185  MultiXactState->nextMXact = nextMulti;
2186  MultiXactState->nextOffset = nextMultiOffset;
2187  LWLockRelease(MultiXactGenLock);
2188 
2189  /*
2190  * During a binary upgrade, make sure that the offsets SLRU is large
2191  * enough to contain the next value that would be created.
2192  *
2193  * We need to do this pretty early during the first startup in binary
2194  * upgrade mode: before StartupMultiXact() in fact, because this routine
2195  * is called even before that by StartupXLOG(). And we can't do it
2196  * earlier than at this point, because during that first call of this
2197  * routine we determine the MultiXactState->nextMXact value that
2198  * MaybeExtendOffsetSlru needs.
2199  */
2200  if (IsBinaryUpgrade)
2202 }
bool IsBinaryUpgrade
Definition: globals.c:114
static void MaybeExtendOffsetSlru(void)
Definition: multixact.c:1975

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

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

◆ MultiXactShmemInit()

void MultiXactShmemInit ( void  )

Definition at line 1844 of file multixact.c.

1845 {
1846  bool found;
1847 
1848  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1849 
1852 
1854  "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
1855  MultiXactOffsetSLRULock, "pg_multixact/offsets",
1860  "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
1861  MultiXactMemberSLRULock, "pg_multixact/members",
1864  /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1865 
1866  /* Initialize our shared state struct */
1867  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1869  &found);
1870  if (!IsUnderPostmaster)
1871  {
1872  Assert(!found);
1873 
1874  /* Make sure we zero out the per-backend state */
1876  }
1877  else
1878  Assert(found);
1879 
1880  /*
1881  * Set up array pointers. Note that perBackendXactIds[0] is wasted space
1882  * since we only use indexes 1..MaxOldestSlot in each array.
1883  */
1886 }
#define MemSet(start, val, len)
Definition: c.h:1009
@ LWTRANCHE_MULTIXACTMEMBER_BUFFER
Definition: lwlock.h:185
@ LWTRANCHE_MULTIXACTOFFSET_BUFFER
Definition: lwlock.h:184
static bool MultiXactOffsetPagePrecedes(int page1, int page2)
Definition: multixact.c:3116
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactMemberPagePrecedes(int page1, int page2)
Definition: multixact.c:3136
#define NUM_MULTIXACTOFFSET_BUFFERS
Definition: multixact.h:33
#define NUM_MULTIXACTMEMBER_BUFFERS
Definition: multixact.h:34
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:396
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:188
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition: slru.h:156
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:283
@ SYNC_HANDLER_MULTIXACT_MEMBER
Definition: sync.h:41
@ SYNC_HANDLER_MULTIXACT_OFFSET
Definition: sync.h:40

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

Referenced by CreateSharedMemoryAndSemaphores().

◆ MultiXactShmemSize()

Size MultiXactShmemSize ( void  )

Definition at line 1827 of file multixact.c.

1828 {
1829  Size size;
1830 
1831  /* We need 2*MaxOldestSlot + 1 perBackendXactIds[] entries */
1832 #define SHARED_MULTIXACT_STATE_SIZE \
1833  add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
1834  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1835 
1839 
1840  return size;
1841 }
size_t Size
Definition: c.h:594
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:156

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

Referenced by CalculateShmemSize().

◆ mXactCacheGetById()

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

Definition at line 1542 of file multixact.c.

1543 {
1544  dlist_iter iter;
1545 
1546  debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
1547 
1548  dclist_foreach(iter, &MXactCache)
1549  {
1551  iter.cur);
1552 
1553  if (entry->multi == multi)
1554  {
1555  MultiXactMember *ptr;
1556  Size size;
1557 
1558  size = sizeof(MultiXactMember) * entry->nmembers;
1559  ptr = (MultiXactMember *) palloc(size);
1560 
1561  memcpy(ptr, entry->members, size);
1562 
1563  debug_elog3(DEBUG2, "CacheGet: found %s",
1564  mxid_to_string(multi,
1565  entry->nmembers,
1566  entry->members));
1567 
1568  /*
1569  * Note we modify the list while not using a modifiable iterator.
1570  * This is acceptable only because we exit the iteration
1571  * immediately afterwards.
1572  */
1574 
1575  *members = ptr;
1576  return entry->nmembers;
1577  }
1578  }
1579 
1580  debug_elog2(DEBUG2, "CacheGet: not found");
1581  return -1;
1582 }
#define dclist_container(type, membername, ptr)
Definition: ilist.h:947
static void dclist_move_head(dclist_head *head, dlist_node *node)
Definition: ilist.h:808
#define dclist_foreach(iter, lhead)
Definition: ilist.h:970
struct MultiXactMember MultiXactMember
dlist_node * cur
Definition: ilist.h:179
MultiXactId multi
Definition: multixact.c:317
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:320

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

Referenced by GetMultiXactIdMembers().

◆ mXactCacheGetBySet()

static MultiXactId mXactCacheGetBySet ( int  nmembers,
MultiXactMember members 
)
static

Definition at line 1499 of file multixact.c.

1500 {
1501  dlist_iter iter;
1502 
1503  debug_elog3(DEBUG2, "CacheGet: looking for %s",
1504  mxid_to_string(InvalidMultiXactId, nmembers, members));
1505 
1506  /* sort the array so comparison is easy */
1507  qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1508 
1509  dclist_foreach(iter, &MXactCache)
1510  {
1512  iter.cur);
1513 
1514  if (entry->nmembers != nmembers)
1515  continue;
1516 
1517  /*
1518  * We assume the cache entries are sorted, and that the unused bits in
1519  * "status" are zeroed.
1520  */
1521  if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
1522  {
1523  debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
1525  return entry->multi;
1526  }
1527  }
1528 
1529  debug_elog2(DEBUG2, "CacheGet: not found :-(");
1530  return InvalidMultiXactId;
1531 }
static int mxactMemberComparator(const void *arg1, const void *arg2)
Definition: multixact.c:1469
#define qsort(a, b, c, d)
Definition: port.h:445

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

Referenced by MultiXactIdCreateFromMembers().

◆ mXactCachePut()

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

Definition at line 1589 of file multixact.c.

1590 {
1591  mXactCacheEnt *entry;
1592 
1593  debug_elog3(DEBUG2, "CachePut: storing %s",
1594  mxid_to_string(multi, nmembers, members));
1595 
1596  if (MXactContext == NULL)
1597  {
1598  /* The cache only lives as long as the current transaction */
1599  debug_elog2(DEBUG2, "CachePut: initializing memory context");
1601  "MultiXact cache context",
1603  }
1604 
1605  entry = (mXactCacheEnt *)
1607  offsetof(mXactCacheEnt, members) +
1608  nmembers * sizeof(MultiXactMember));
1609 
1610  entry->multi = multi;
1611  entry->nmembers = nmembers;
1612  memcpy(entry->members, members, nmembers * sizeof(MultiXactMember));
1613 
1614  /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
1615  qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1616 
1617  dclist_push_head(&MXactCache, &entry->node);
1619  {
1620  dlist_node *node;
1621 
1622  node = dclist_tail_node(&MXactCache);
1624 
1625  entry = dclist_container(mXactCacheEnt, node, node);
1626  debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
1627  entry->multi);
1628 
1629  pfree(entry);
1630  }
1631 }
static dlist_node * dclist_tail_node(dclist_head *head)
Definition: ilist.h:920
static uint32 dclist_count(const dclist_head *head)
Definition: ilist.h:932
static void dclist_delete_from(dclist_head *head, dlist_node *node)
Definition: ilist.h:763
static void dclist_push_head(dclist_head *head, dlist_node *node)
Definition: ilist.h:693
MemoryContext TopTransactionContext
Definition: mcxt.c:146
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:1021
#define AllocSetContextCreate
Definition: memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition: memutils.h:163
#define MAX_CACHE_ENTRIES
Definition: multixact.c:323
dlist_node node
Definition: multixact.c:319

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, dclist_container, dclist_count(), dclist_delete_from(), dclist_push_head(), dclist_tail_node(), DEBUG2, debug_elog2, debug_elog3, MAX_CACHE_ENTRIES, mXactCacheEnt::members, MemoryContextAlloc(), mXactCacheEnt::multi, MXactCache, MXactContext, mxactMemberComparator(), mxid_to_string(), mXactCacheEnt::nmembers, mXactCacheEnt::node, pfree(), qsort, and TopTransactionContext.

Referenced by GetMultiXactIdMembers(), and MultiXactIdCreateFromMembers().

◆ mxactMemberComparator()

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

Definition at line 1469 of file multixact.c.

1470 {
1471  MultiXactMember member1 = *(const MultiXactMember *) arg1;
1472  MultiXactMember member2 = *(const MultiXactMember *) arg2;
1473 
1474  if (member1.xid > member2.xid)
1475  return 1;
1476  if (member1.xid < member2.xid)
1477  return -1;
1478  if (member1.status > member2.status)
1479  return 1;
1480  if (member1.status < member2.status)
1481  return -1;
1482  return 0;
1483 }

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

Referenced by mXactCacheGetBySet(), and mXactCachePut().

◆ mxid_to_string()

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

Definition at line 1657 of file multixact.c.

1658 {
1659  static char *str = NULL;
1661  int i;
1662 
1663  if (str != NULL)
1664  pfree(str);
1665 
1666  initStringInfo(&buf);
1667 
1668  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1669  mxstatus_to_string(members[0].status));
1670 
1671  for (i = 1; i < nmembers; i++)
1672  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1673  mxstatus_to_string(members[i].status));
1674 
1675  appendStringInfoChar(&buf, ']');
1677  pfree(buf.data);
1678  return str;
1679 }
MemoryContext TopMemoryContext
Definition: mcxt.c:141
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1631
static char * buf
Definition: pg_test_fsync.c:67
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:91
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:188
void initStringInfo(StringInfo str)
Definition: stringinfo.c:59

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

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

◆ mxstatus_to_string()

static char * mxstatus_to_string ( MultiXactStatus  status)
static

Definition at line 1634 of file multixact.c.

1635 {
1636  switch (status)
1637  {
1639  return "keysh";
1641  return "sh";
1643  return "fornokeyupd";
1645  return "forupd";
1647  return "nokeyupd";
1648  case MultiXactStatusUpdate:
1649  return "upd";
1650  default:
1651  elog(ERROR, "unrecognized multixact status %d", status);
1652  return "";
1653  }
1654 }
@ MultiXactStatusForShare
Definition: multixact.h:44
@ MultiXactStatusForNoKeyUpdate
Definition: multixact.h:45
@ MultiXactStatusNoKeyUpdate
Definition: multixact.h:48
@ MultiXactStatusUpdate
Definition: multixact.h:50
@ MultiXactStatusForUpdate
Definition: multixact.h:46
@ MultiXactStatusForKeyShare
Definition: multixact.h:43

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

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

◆ PerformMembersTruncation()

static void PerformMembersTruncation ( MultiXactOffset  oldestOffset,
MultiXactOffset  newOldestOffset 
)
static

Definition at line 2888 of file multixact.c.

2889 {
2890  const int maxsegment = MXOffsetToMemberSegment(MaxMultiXactOffset);
2891  int startsegment = MXOffsetToMemberSegment(oldestOffset);
2892  int endsegment = MXOffsetToMemberSegment(newOldestOffset);
2893  int segment = startsegment;
2894 
2895  /*
2896  * Delete all the segments but the last one. The last segment can still
2897  * contain, possibly partially, valid data.
2898  */
2899  while (segment != endsegment)
2900  {
2901  elog(DEBUG2, "truncating multixact members segment %x", segment);
2903 
2904  /* move to next segment, handling wraparound correctly */
2905  if (segment == maxsegment)
2906  segment = 0;
2907  else
2908  segment += 1;
2909  }
2910 }
void SlruDeleteSegment(SlruCtl ctl, int segno)
Definition: slru.c:1328

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

Referenced by multixact_redo(), and TruncateMultiXact().

◆ PerformOffsetsTruncation()

static void PerformOffsetsTruncation ( MultiXactId  oldestMulti,
MultiXactId  newOldestMulti 
)
static

Definition at line 2916 of file multixact.c.

2917 {
2918  /*
2919  * We step back one multixact to avoid passing a cutoff page that hasn't
2920  * been created yet in the rare case that oldestMulti would be the first
2921  * item on a page and oldestMulti == nextMulti. In that case, if we
2922  * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
2923  * detection.
2924  */
2926  MultiXactIdToOffsetPage(PreviousMultiXactId(newOldestMulti)));
2927 }
#define PreviousMultiXactId(xid)
Definition: multixact.c:181
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1227

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

Referenced by multixact_redo(), and TruncateMultiXact().

◆ pg_get_multixact_members()

Datum pg_get_multixact_members ( PG_FUNCTION_ARGS  )

Definition at line 3344 of file multixact.c.

3345 {
3346  typedef struct
3347  {
3348  MultiXactMember *members;
3349  int nmembers;
3350  int iter;
3351  } mxact;
3353  mxact *multi;
3354  FuncCallContext *funccxt;
3355 
3356  if (mxid < FirstMultiXactId)
3357  ereport(ERROR,
3358  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3359  errmsg("invalid MultiXactId: %u", mxid)));
3360 
3361  if (SRF_IS_FIRSTCALL())
3362  {
3363  MemoryContext oldcxt;
3364  TupleDesc tupdesc;
3365 
3366  funccxt = SRF_FIRSTCALL_INIT();
3367  oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx);
3368 
3369  multi = palloc(sizeof(mxact));
3370  /* no need to allow for old values here */
3371  multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
3372  false);
3373  multi->iter = 0;
3374 
3375  if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
3376  elog(ERROR, "return type must be a row type");
3377  funccxt->tuple_desc = tupdesc;
3378  funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
3379  funccxt->user_fctx = multi;
3380 
3381  MemoryContextSwitchTo(oldcxt);
3382  }
3383 
3384  funccxt = SRF_PERCALL_SETUP();
3385  multi = (mxact *) funccxt->user_fctx;
3386 
3387  while (multi->iter < multi->nmembers)
3388  {
3389  HeapTuple tuple;
3390  char *values[2];
3391 
3392  values[0] = psprintf("%u", multi->members[multi->iter].xid);
3393  values[1] = mxstatus_to_string(multi->members[multi->iter].status);
3394 
3395  tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
3396 
3397  multi->iter++;
3398  pfree(values[0]);
3399  SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
3400  }
3401 
3402  SRF_RETURN_DONE(funccxt);
3403 }
static Datum values[MAXATTR]
Definition: bootstrap.c:156
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2136
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2087
#define PG_GETARG_TRANSACTIONID(n)
Definition: fmgr.h:279
TypeFuncClass get_call_result_type(FunctionCallInfo fcinfo, Oid *resultTypeId, TupleDesc *resultTupleDesc)
Definition: funcapi.c:276
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:304
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:308
@ TYPEFUNC_COMPOSITE
Definition: funcapi.h:149
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:310
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:306
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:328
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:138
while(p+4<=pend)
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
void * user_fctx
Definition: funcapi.h:82
AttInMetadata * attinmeta
Definition: funcapi.h:91
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:101
TupleDesc tuple_desc
Definition: funcapi.h:112

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

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1730 of file multixact.c.

1731 {
1732  MultiXactId myOldestMember;
1733 
1734  /*
1735  * Transfer our OldestMemberMXactId value to the slot reserved for the
1736  * prepared transaction.
1737  */
1738  myOldestMember = OldestMemberMXactId[MyBackendId];
1739  if (MultiXactIdIsValid(myOldestMember))
1740  {
1741  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid, false);
1742 
1743  /*
1744  * Even though storing MultiXactId is atomic, acquire lock to make
1745  * sure others see both changes, not just the reset of the slot of the
1746  * current backend. Using a volatile pointer might suffice, but this
1747  * isn't a hot spot.
1748  */
1749  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1750 
1751  OldestMemberMXactId[dummyBackendId] = myOldestMember;
1753 
1754  LWLockRelease(MultiXactGenLock);
1755  }
1756 
1757  /*
1758  * We don't need to transfer OldestVisibleMXactId value, because the
1759  * transaction is not going to be looking at any more multixacts once it's
1760  * prepared.
1761  *
1762  * We assume that storing a MultiXactId is atomic and so we need not take
1763  * MultiXactGenLock to do this.
1764  */
1766 
1767  /*
1768  * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1769  */
1770  MXactContext = NULL;
1772 }

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

Referenced by PrepareTransaction().

◆ ReadMultiXactCounts()

static bool ReadMultiXactCounts ( uint32 multixacts,
MultiXactOffset members 
)
static

Definition at line 2773 of file multixact.c.

2774 {
2775  MultiXactOffset nextOffset;
2776  MultiXactOffset oldestOffset;
2777  MultiXactId oldestMultiXactId;
2778  MultiXactId nextMultiXactId;
2779  bool oldestOffsetKnown;
2780 
2781  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2782  nextOffset = MultiXactState->nextOffset;
2783  oldestMultiXactId = MultiXactState->oldestMultiXactId;
2784  nextMultiXactId = MultiXactState->nextMXact;
2785  oldestOffset = MultiXactState->oldestOffset;
2786  oldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2787  LWLockRelease(MultiXactGenLock);
2788 
2789  if (!oldestOffsetKnown)
2790  return false;
2791 
2792  *members = nextOffset - oldestOffset;
2793  *multixacts = nextMultiXactId - oldestMultiXactId;
2794  return true;
2795 }

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

Referenced by MultiXactMemberFreezeThreshold().

◆ ReadMultiXactIdRange()

void ReadMultiXactIdRange ( MultiXactId oldest,
MultiXactId next 
)

Definition at line 744 of file multixact.c.

745 {
746  LWLockAcquire(MultiXactGenLock, LW_SHARED);
749  LWLockRelease(MultiXactGenLock);
750 
751  if (*oldest < FirstMultiXactId)
752  *oldest = FirstMultiXactId;
753  if (*next < FirstMultiXactId)
755 }
static int32 next
Definition: blutils.c:219

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

Referenced by update_cached_mxid_range().

◆ ReadNextMultiXactId()

MultiXactId ReadNextMultiXactId ( void  )

Definition at line 724 of file multixact.c.

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

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

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

◆ RecordNewMultiXact()

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

Definition at line 864 of file multixact.c.

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

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

Referenced by multixact_redo(), and MultiXactIdCreateFromMembers().

◆ SetMultiXactIdLimit()

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

Definition at line 2213 of file multixact.c.

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

References Assert(), autovacuum_multixact_freeze_max_age, DEBUG1, ereport, errhint(), errmsg_internal(), errmsg_plural(), MultiXactStateData::finishedStartup, FirstMultiXactId, get_database_name(), InRecovery, IsTransactionState(), IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaxMultiXactId, MultiXactStateData::multiStopLimit, MultiXactStateData::multiVacLimit, MultiXactStateData::multiWarnLimit, MultiXactStateData::multiWrapLimit, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactState, MultiXactStateData::nextMXact, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestMultiXactId, PMSIGNAL_START_AUTOVAC_LAUNCHER, SendPostmasterSignal(), SetOffsetVacuumLimit(), and WARNING.

Referenced by BootStrapXLOG(), multixact_redo(), MultiXactAdvanceOldest(), StartupXLOG(), TrimMultiXact(), and vac_truncate_clog().

◆ SetOffsetVacuumLimit()

static bool SetOffsetVacuumLimit ( bool  is_startup)
static

Definition at line 2560 of file multixact.c.

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

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

Referenced by SetMultiXactIdLimit().

◆ SlruScanDirCbFindEarliest()

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

Definition at line 2865 of file multixact.c.

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

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

Referenced by TruncateMultiXact().

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 2008 of file multixact.c.

2009 {
2012  int pageno;
2013 
2014  /*
2015  * Initialize offset's idea of the latest page number.
2016  */
2017  pageno = MultiXactIdToOffsetPage(multi);
2018  MultiXactOffsetCtl->shared->latest_page_number = pageno;
2019 
2020  /*
2021  * Initialize member's idea of the latest page number.
2022  */
2023  pageno = MXOffsetToMemberPage(offset);
2024  MultiXactMemberCtl->shared->latest_page_number = pageno;
2025 }

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

Referenced by StartupXLOG().

◆ TrimMultiXact()

void TrimMultiXact ( void  )

Definition at line 2031 of file multixact.c.

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

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

Referenced by StartupXLOG().

◆ TruncateMultiXact()

void TruncateMultiXact ( MultiXactId  newOldestMulti,
Oid  newOldestMultiDB 
)

Definition at line 2941 of file multixact.c.

2942 {
2943  MultiXactId oldestMulti;
2944  MultiXactId nextMulti;
2945  MultiXactOffset newOldestOffset;
2946  MultiXactOffset oldestOffset;
2947  MultiXactOffset nextOffset;
2948  mxtruncinfo trunc;
2949  MultiXactId earliest;
2950 
2953 
2954  /*
2955  * We can only allow one truncation to happen at once. Otherwise parts of
2956  * members might vanish while we're doing lookups or similar. There's no
2957  * need to have an interlock with creating new multis or such, since those
2958  * are constrained by the limits (which only grow, never shrink).
2959  */
2960  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
2961 
2962  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2963  nextMulti = MultiXactState->nextMXact;
2964  nextOffset = MultiXactState->nextOffset;
2965  oldestMulti = MultiXactState->oldestMultiXactId;
2966  LWLockRelease(MultiXactGenLock);
2967  Assert(MultiXactIdIsValid(oldestMulti));
2968 
2969  /*
2970  * Make sure to only attempt truncation if there's values to truncate
2971  * away. In normal processing values shouldn't go backwards, but there's
2972  * some corner cases (due to bugs) where that's possible.
2973  */
2974  if (MultiXactIdPrecedesOrEquals(newOldestMulti, oldestMulti))
2975  {
2976  LWLockRelease(MultiXactTruncationLock);
2977  return;
2978  }
2979 
2980  /*
2981  * Note we can't just plow ahead with the truncation; it's possible that
2982  * there are no segments to truncate, which is a problem because we are
2983  * going to attempt to read the offsets page to determine where to
2984  * truncate the members SLRU. So we first scan the directory to determine
2985  * the earliest offsets page number that we can read without error.
2986  *
2987  * When nextMXact is less than one segment away from multiWrapLimit,
2988  * SlruScanDirCbFindEarliest can find some early segment other than the
2989  * actual earliest. (MultiXactOffsetPagePrecedes(EARLIEST, LATEST)
2990  * returns false, because not all pairs of entries have the same answer.)
2991  * That can also arise when an earlier truncation attempt failed unlink()
2992  * or returned early from this function. The only consequence is
2993  * returning early, which wastes space that we could have liberated.
2994  *
2995  * NB: It's also possible that the page that oldestMulti is on has already
2996  * been truncated away, and we crashed before updating oldestMulti.
2997  */
2998  trunc.earliestExistingPage = -1;
3001  if (earliest < FirstMultiXactId)
3002  earliest = FirstMultiXactId;
3003 
3004  /* If there's nothing to remove, we can bail out early. */
3005  if (MultiXactIdPrecedes(oldestMulti, earliest))
3006  {
3007  LWLockRelease(MultiXactTruncationLock);
3008  return;
3009  }
3010 
3011  /*
3012  * First, compute the safe truncation point for MultiXactMember. This is
3013  * the starting offset of the oldest multixact.
3014  *
3015  * Hopefully, find_multixact_start will always work here, because we've
3016  * already checked that it doesn't precede the earliest MultiXact on disk.
3017  * But if it fails, don't truncate anything, and log a message.
3018  */
3019  if (oldestMulti == nextMulti)
3020  {
3021  /* there are NO MultiXacts */
3022  oldestOffset = nextOffset;
3023  }
3024  else if (!find_multixact_start(oldestMulti, &oldestOffset))
3025  {
3026  ereport(LOG,
3027  (errmsg("oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation",
3028  oldestMulti, earliest)));
3029  LWLockRelease(MultiXactTruncationLock);
3030  return;
3031  }
3032 
3033  /*
3034  * Secondly compute up to where to truncate. Lookup the corresponding
3035  * member offset for newOldestMulti for that.
3036  */
3037  if (newOldestMulti == nextMulti)
3038  {
3039  /* there are NO MultiXacts */
3040  newOldestOffset = nextOffset;
3041  }
3042  else if (!find_multixact_start(newOldestMulti, &newOldestOffset))
3043  {
3044  ereport(LOG,
3045  (errmsg("cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
3046  newOldestMulti)));
3047  LWLockRelease(MultiXactTruncationLock);
3048  return;
3049  }
3050 
3051  elog(DEBUG1, "performing multixact truncation: "
3052  "offsets [%u, %u), offsets segments [%x, %x), "
3053  "members [%u, %u), members segments [%x, %x)",
3054  oldestMulti, newOldestMulti,
3055  MultiXactIdToOffsetSegment(oldestMulti),
3056  MultiXactIdToOffsetSegment(newOldestMulti),
3057  oldestOffset, newOldestOffset,
3058  MXOffsetToMemberSegment(oldestOffset),
3059  MXOffsetToMemberSegment(newOldestOffset));
3060 
3061  /*
3062  * Do truncation, and the WAL logging of the truncation, in a critical
3063  * section. That way offsets/members cannot get out of sync anymore, i.e.
3064  * once consistent the newOldestMulti will always exist in members, even
3065  * if we crashed in the wrong moment.
3066  */
3068 
3069  /*
3070  * Prevent checkpoints from being scheduled concurrently. This is critical
3071  * because otherwise a truncation record might not be replayed after a
3072  * crash/basebackup, even though the state of the data directory would
3073  * require it.
3074  */
3077 
3078  /* WAL log truncation */
3079  WriteMTruncateXlogRec(newOldestMultiDB,
3080  oldestMulti, newOldestMulti,
3081  oldestOffset, newOldestOffset);
3082 
3083  /*
3084  * Update in-memory limits before performing the truncation, while inside
3085  * the critical section: Have to do it before truncation, to prevent
3086  * concurrent lookups of those values. Has to be inside the critical
3087  * section as otherwise a future call to this function would error out,
3088  * while looking up the oldest member in offsets, if our caller crashes
3089  * before updating the limits.
3090  */
3091  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
3092  MultiXactState->oldestMultiXactId = newOldestMulti;
3093  MultiXactState->oldestMultiXactDB = newOldestMultiDB;
3094  LWLockRelease(MultiXactGenLock);
3095 
3096  /* First truncate members */
3097  PerformMembersTruncation(oldestOffset, newOldestOffset);
3098 
3099  /* Then offsets */
3100  PerformOffsetsTruncation(oldestMulti, newOldestMulti);
3101 
3103 
3104  END_CRIT_SECTION();
3105  LWLockRelease(MultiXactTruncationLock);
3106 }
static void WriteMTruncateXlogRec(Oid oldestMultiDB, MultiXactId startTruncOff, MultiXactId endTruncOff, MultiXactOffset startTruncMemb, MultiXactOffset endTruncMemb)
Definition: multixact.c:3208
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3170
static bool SlruScanDirCbFindEarliest(SlruCtl ctl, char *filename, int segpage, void *data)
Definition: multixact.c:2865
#define DELAY_CHKPT_START
Definition: proc.h:119
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1554
PGPROC * MyProc
Definition: proc.c:66
int delayChkptFlags
Definition: proc.h:231

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

Referenced by vac_truncate_clog().

◆ WriteMTruncateXlogRec()

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

Definition at line 3208 of file multixact.c.

3211 {
3212  XLogRecPtr recptr;
3213  xl_multixact_truncate xlrec;
3214 
3215  xlrec.oldestMultiDB = oldestMultiDB;
3216 
3217  xlrec.startTruncOff = startTruncOff;
3218  xlrec.endTruncOff = endTruncOff;
3219 
3220  xlrec.startTruncMemb = startTruncMemb;
3221  xlrec.endTruncMemb = endTruncMemb;
3222 
3223  XLogBeginInsert();
3224  XLogRegisterData((char *) (&xlrec), SizeOfMultiXactTruncate);
3225  recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
3226  XLogFlush(recptr);
3227 }
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2535
uint64 XLogRecPtr
Definition: xlogdefs.h:21

References xl_multixact_truncate::endTruncMemb, xl_multixact_truncate::endTruncOff, xl_multixact_truncate::oldestMultiDB, SizeOfMultiXactTruncate, xl_multixact_truncate::startTruncMemb, xl_multixact_truncate::startTruncOff, XLOG_MULTIXACT_TRUNCATE_ID, XLogBeginInsert(), XLogFlush(), XLogInsert(), and XLogRegisterData().

Referenced by TruncateMultiXact().

◆ WriteMZeroPageXlogRec()

static void WriteMZeroPageXlogRec ( int  pageno,
uint8  info 
)
static

Definition at line 3194 of file multixact.c.

3195 {
3196  XLogBeginInsert();
3197  XLogRegisterData((char *) (&pageno), sizeof(int));
3198  (void) XLogInsert(RM_MULTIXACT_ID, info);
3199 }

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

Referenced by ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

◆ ZeroMultiXactMemberPage()

static int ZeroMultiXactMemberPage ( int  pageno,
bool  writeXlog 
)
static

Definition at line 1947 of file multixact.c.

1948 {
1949  int slotno;
1950 
1951  slotno = SimpleLruZeroPage(MultiXactMemberCtl, pageno);
1952 
1953  if (writeXlog)
1955 
1956  return slotno;
1957 }
static void WriteMZeroPageXlogRec(int pageno, uint8 info)
Definition: multixact.c:3194
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:281

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

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

◆ ZeroMultiXactOffsetPage()

static int ZeroMultiXactOffsetPage ( int  pageno,
bool  writeXlog 
)
static

Definition at line 1931 of file multixact.c.

1932 {
1933  int slotno;
1934 
1935  slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
1936 
1937  if (writeXlog)
1939 
1940  return slotno;
1941 }

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

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

Variable Documentation

◆ MultiXactMemberCtlData

SlruCtlData MultiXactMemberCtlData
static

Definition at line 188 of file multixact.c.

◆ MultiXactOffsetCtlData

SlruCtlData MultiXactOffsetCtlData
static

Definition at line 187 of file multixact.c.

◆ MultiXactState

◆ MXactCache

◆ MXactContext

MemoryContext MXactContext = NULL
static

Definition at line 325 of file multixact.c.

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

◆ OldestMemberMXactId

◆ OldestVisibleMXactId