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

◆ debug_elog3

#define debug_elog3 (   a,
  b,
  c 
)

Definition at line 333 of file multixact.c.

◆ debug_elog4

#define debug_elog4 (   a,
  b,
  c,
 
)

Definition at line 334 of file multixact.c.

◆ debug_elog5

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

Definition at line 335 of file multixact.c.

◆ debug_elog6

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

Definition at line 336 of file multixact.c.

◆ MAX_CACHE_ENTRIES

#define MAX_CACHE_ENTRIES   256

Definition at line 321 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 288 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:588
#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:598
#define MaxOldestSlot
Definition: multixact.c:288
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 1686 of file multixact.c.

1687 {
1688  /*
1689  * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1690  * which should only be valid while within a transaction.
1691  *
1692  * We assume that storing a MultiXactId is atomic and so we need not take
1693  * MultiXactGenLock to do this.
1694  */
1697 
1698  /*
1699  * Discard the local MultiXactId cache. Since MXactContext was created as
1700  * a child of TopTransactionContext, we needn't delete it explicitly.
1701  */
1702  MXactContext = NULL;
1704 }
BackendId MyBackendId
Definition: globals.c:85
static void dclist_init(dclist_head *head)
Definition: ilist.h:621
static MemoryContext MXactContext
Definition: multixact.c:323
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
static dclist_head MXactCache
Definition: multixact.c:322
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
#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 1714 of file multixact.c.

1715 {
1716  MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId];
1717 
1718  if (MultiXactIdIsValid(myOldestMember))
1720  &myOldestMember, sizeof(MultiXactId));
1721 }
#define MultiXactIdIsValid(multi)
Definition: multixact.h:28
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1257
#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 1892 of file multixact.c.

1893 {
1894  int slotno;
1895 
1896  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
1897 
1898  /* Create and zero the first page of the offsets log */
1899  slotno = ZeroMultiXactOffsetPage(0, false);
1900 
1901  /* Make sure it's written out */
1903  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1904 
1905  LWLockRelease(MultiXactOffsetSLRULock);
1906 
1907  LWLockAcquire(MultiXactMemberSLRULock, LW_EXCLUSIVE);
1908 
1909  /* Create and zero the first page of the members log */
1910  slotno = ZeroMultiXactMemberPage(0, false);
1911 
1912  /* Make sure it's written out */
1914  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
1915 
1916  LWLockRelease(MultiXactMemberSLRULock);
1917 }
Assert(fmt[strlen(fmt) - 1] !='\n')
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1194
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1802
@ LW_EXCLUSIVE
Definition: lwlock.h:112
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1945
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1929
#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 2153 of file multixact.c.

2154 {
2155  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2156 
2157  /*
2158  * Write dirty MultiXact pages to disk. This may result in sync requests
2159  * queued for later handling by ProcessSyncRequests(), as part of the
2160  * checkpoint.
2161  */
2164 
2165  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2166 }
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 2432 of file multixact.c.

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

2403 {
2404  int pageno;
2405 
2406  /*
2407  * No work except at first MultiXactId of a page. But beware: just after
2408  * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2409  */
2410  if (MultiXactIdToOffsetEntry(multi) != 0 &&
2411  multi != FirstMultiXactId)
2412  return;
2413 
2414  pageno = MultiXactIdToOffsetPage(multi);
2415 
2416  LWLockAcquire(MultiXactOffsetSLRULock, LW_EXCLUSIVE);
2417 
2418  /* Zero the page and make an XLOG entry about it */
2419  ZeroMultiXactOffsetPage(pageno, true);
2420 
2421  LWLockRelease(MultiXactOffsetSLRULock);
2422 }
#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 2732 of file multixact.c.

2733 {
2734  MultiXactOffset offset;
2735  int pageno;
2736  int entryno;
2737  int slotno;
2738  MultiXactOffset *offptr;
2739 
2741 
2742  pageno = MultiXactIdToOffsetPage(multi);
2743  entryno = MultiXactIdToOffsetEntry(multi);
2744 
2745  /*
2746  * Write out dirty data, so PhysicalPageExists can work correctly.
2747  */
2750 
2752  return false;
2753 
2754  /* lock is acquired by SimpleLruReadPage_ReadOnly */
2755  slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
2756  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2757  offptr += entryno;
2758  offset = *offptr;
2759  LWLockRelease(MultiXactOffsetSLRULock);
2760 
2761  *result = offset;
2762  return true;
2763 }
uint32 MultiXactOffset
Definition: c.h:600
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
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 1223 of file multixact.c.

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

◆ GetNewMultiXactId()

static MultiXactId GetNewMultiXactId ( int  nmembers,
MultiXactOffset offset 
)
static

Definition at line 956 of file multixact.c.

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

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

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

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

◆ MaybeExtendOffsetSlru()

static void MaybeExtendOffsetSlru ( void  )
static

Definition at line 1973 of file multixact.c.

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

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

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

1815 {
1816  multixact_twophase_postcommit(xid, info, recdata, len);
1817 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1798
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 1798 of file multixact.c.

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

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

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

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2360 of file multixact.c.

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

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

2386 {
2387  Assert(InRecovery);
2388 
2390  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2391 }
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 2131 of file multixact.c.

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

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

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

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

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

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, status(), TransactionIdDidCommit(), TransactionIdEquals, TransactionIdIsInProgress(), TransactionIdIsValid, and MultiXactMember::xid.

Referenced by compute_new_xmax_infomask().

◆ MultiXactIdIsRunning()

bool MultiXactIdIsRunning ( MultiXactId  multi,
bool  isLockOnly 
)

Definition at line 550 of file multixact.c.

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

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

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

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

◆ MultiXactIdSetOldestMember()

void MultiXactIdSetOldestMember ( void  )

Definition at line 624 of file multixact.c.

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

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

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

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

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

◆ MultiXactMemberPagePrecedes()

static bool MultiXactMemberPagePrecedes ( int  page1,
int  page2 
)
static

Definition at line 3137 of file multixact.c.

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

References MULTIXACT_MEMBERS_PER_PAGE, and MultiXactOffsetPrecedes().

Referenced by MultiXactShmemInit().

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3422 of file multixact.c.

3423 {
3424  return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3425 }
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 3117 of file multixact.c.

3118 {
3119  MultiXactId multi1;
3120  MultiXactId multi2;
3121 
3122  multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
3123  multi1 += FirstMultiXactId + 1;
3124  multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
3125  multi2 += FirstMultiXactId + 1;
3126 
3127  return (MultiXactIdPrecedes(multi1, multi2) &&
3128  MultiXactIdPrecedes(multi1,
3129  multi2 + MULTIXACT_OFFSETS_PER_PAGE - 1));
3130 }
#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 3183 of file multixact.c.

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

Referenced by MultiXactAdvanceNextMXact(), and MultiXactMemberPagePrecedes().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 3413 of file multixact.c.

3414 {
3415  return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3416 }

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactOffsetWouldWrap()

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

Definition at line 2684 of file multixact.c.

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

Referenced by GetNewMultiXactId().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2177 of file multixact.c.

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

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

1843 {
1844  bool found;
1845 
1846  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1847 
1850 
1852  "MultiXactOffset", NUM_MULTIXACTOFFSET_BUFFERS, 0,
1853  MultiXactOffsetSLRULock, "pg_multixact/offsets",
1858  "MultiXactMember", NUM_MULTIXACTMEMBER_BUFFERS, 0,
1859  MultiXactMemberSLRULock, "pg_multixact/members",
1862  /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1863 
1864  /* Initialize our shared state struct */
1865  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1867  &found);
1868  if (!IsUnderPostmaster)
1869  {
1870  Assert(!found);
1871 
1872  /* Make sure we zero out the per-backend state */
1874  }
1875  else
1876  Assert(found);
1877 
1878  /*
1879  * Set up array pointers. Note that perBackendXactIds[0] is wasted space
1880  * since we only use indexes 1..MaxOldestSlot in each array.
1881  */
1884 }
#define MemSet(start, val, len)
Definition: c.h:953
@ LWTRANCHE_MULTIXACTMEMBER_BUFFER
Definition: lwlock.h:181
@ LWTRANCHE_MULTIXACTOFFSET_BUFFER
Definition: lwlock.h:180
static bool MultiXactOffsetPagePrecedes(int page1, int page2)
Definition: multixact.c:3117
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactMemberPagePrecedes(int page1, int page2)
Definition: multixact.c:3137
#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:281
@ 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 1825 of file multixact.c.

1826 {
1827  Size size;
1828 
1829  /* We need 2*MaxOldestSlot + 1 perBackendXactIds[] entries */
1830 #define SHARED_MULTIXACT_STATE_SIZE \
1831  add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
1832  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1833 
1837 
1838  return size;
1839 }
size_t Size
Definition: c.h:541
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 1540 of file multixact.c.

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

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

1498 {
1499  dlist_iter iter;
1500 
1501  debug_elog3(DEBUG2, "CacheGet: looking for %s",
1502  mxid_to_string(InvalidMultiXactId, nmembers, members));
1503 
1504  /* sort the array so comparison is easy */
1505  qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1506 
1507  dclist_foreach(iter, &MXactCache)
1508  {
1510  iter.cur);
1511 
1512  if (entry->nmembers != nmembers)
1513  continue;
1514 
1515  /*
1516  * We assume the cache entries are sorted, and that the unused bits in
1517  * "status" are zeroed.
1518  */
1519  if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
1520  {
1521  debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
1523  return entry->multi;
1524  }
1525  }
1526 
1527  debug_elog2(DEBUG2, "CacheGet: not found :-(");
1528  return InvalidMultiXactId;
1529 }
static int mxactMemberComparator(const void *arg1, const void *arg2)
Definition: multixact.c:1467
#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 1587 of file multixact.c.

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

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

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

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

1656 {
1657  static char *str = NULL;
1659  int i;
1660 
1661  if (str != NULL)
1662  pfree(str);
1663 
1664  initStringInfo(&buf);
1665 
1666  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1667  mxstatus_to_string(members[0].status));
1668 
1669  for (i = 1; i < nmembers; i++)
1670  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1671  mxstatus_to_string(members[i].status));
1672 
1673  appendStringInfoChar(&buf, ']');
1675  pfree(buf.data);
1676  return str;
1677 }
MemoryContext TopMemoryContext
Definition: mcxt.c:130
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1470
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(), status(), 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 1632 of file multixact.c.

1633 {
1634  switch (status)
1635  {
1637  return "keysh";
1639  return "sh";
1641  return "fornokeyupd";
1643  return "forupd";
1645  return "nokeyupd";
1646  case MultiXactStatusUpdate:
1647  return "upd";
1648  default:
1649  elog(ERROR, "unrecognized multixact status %d", status);
1650  return "";
1651  }
1652 }
@ 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, MultiXactStatusUpdate, and status().

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

◆ PerformMembersTruncation()

static void PerformMembersTruncation ( MultiXactOffset  oldestOffset,
MultiXactOffset  newOldestOffset 
)
static

Definition at line 2889 of file multixact.c.

2890 {
2891  const int maxsegment = MXOffsetToMemberSegment(MaxMultiXactOffset);
2892  int startsegment = MXOffsetToMemberSegment(oldestOffset);
2893  int endsegment = MXOffsetToMemberSegment(newOldestOffset);
2894  int segment = startsegment;
2895 
2896  /*
2897  * Delete all the segments but the last one. The last segment can still
2898  * contain, possibly partially, valid data.
2899  */
2900  while (segment != endsegment)
2901  {
2902  elog(DEBUG2, "truncating multixact members segment %x", segment);
2904 
2905  /* move to next segment, handling wraparound correctly */
2906  if (segment == maxsegment)
2907  segment = 0;
2908  else
2909  segment += 1;
2910  }
2911 }
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 2917 of file multixact.c.

2918 {
2919  /*
2920  * We step back one multixact to avoid passing a cutoff page that hasn't
2921  * been created yet in the rare case that oldestMulti would be the first
2922  * item on a page and oldestMulti == nextMulti. In that case, if we
2923  * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
2924  * detection.
2925  */
2927  MultiXactIdToOffsetPage(PreviousMultiXactId(newOldestMulti)));
2928 }
#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 3345 of file multixact.c.

3346 {
3347  typedef struct
3348  {
3349  MultiXactMember *members;
3350  int nmembers;
3351  int iter;
3352  } mxact;
3354  mxact *multi;
3355  FuncCallContext *funccxt;
3356 
3357  if (mxid < FirstMultiXactId)
3358  ereport(ERROR,
3359  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3360  errmsg("invalid MultiXactId: %u", mxid)));
3361 
3362  if (SRF_IS_FIRSTCALL())
3363  {
3364  MemoryContext oldcxt;
3365  TupleDesc tupdesc;
3366 
3367  funccxt = SRF_FIRSTCALL_INIT();
3368  oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx);
3369 
3370  multi = palloc(sizeof(mxact));
3371  /* no need to allow for old values here */
3372  multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
3373  false);
3374  multi->iter = 0;
3375 
3376  tupdesc = CreateTemplateTupleDesc(2);
3377  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "xid",
3378  XIDOID, -1, 0);
3379  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "mode",
3380  TEXTOID, -1, 0);
3381 
3382  funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
3383  funccxt->user_fctx = multi;
3384 
3385  MemoryContextSwitchTo(oldcxt);
3386  }
3387 
3388  funccxt = SRF_PERCALL_SETUP();
3389  multi = (mxact *) funccxt->user_fctx;
3390 
3391  while (multi->iter < multi->nmembers)
3392  {
3393  HeapTuple tuple;
3394  char *values[2];
3395 
3396  values[0] = psprintf("%u", multi->members[multi->iter].xid);
3397  values[1] = mxstatus_to_string(multi->members[multi->iter].status);
3398 
3399  tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
3400 
3401  multi->iter++;
3402  pfree(values[0]);
3403  SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
3404  }
3405 
3406  SRF_RETURN_DONE(funccxt);
3407 }
int16 AttrNumber
Definition: attnum.h:21
static Datum values[MAXATTR]
Definition: bootstrap.c:156
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:2135
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:2086
#define PG_GETARG_TRANSACTIONID(n)
Definition: fmgr.h:279
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:303
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:307
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:309
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:305
static Datum HeapTupleGetDatum(const HeapTupleData *tuple)
Definition: funcapi.h:230
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:327
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:135
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 CreateTemplateTupleDesc(int natts)
Definition: tupdesc.c:45
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:583

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

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1728 of file multixact.c.

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

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

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

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

743 {
744  LWLockAcquire(MultiXactGenLock, LW_SHARED);
747  LWLockRelease(MultiXactGenLock);
748 
749  if (*oldest < FirstMultiXactId)
750  *oldest = FirstMultiXactId;
751  if (*next < FirstMultiXactId)
753 }
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 722 of file multixact.c.

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

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

◆ RecordNewMultiXact()

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

Definition at line 862 of file multixact.c.

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

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

Referenced by multixact_redo(), and MultiXactIdCreateFromMembers().

◆ SetMultiXactIdLimit()

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

Definition at line 2211 of file multixact.c.

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

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

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

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

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

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

Referenced by TruncateMultiXact().

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 2006 of file multixact.c.

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

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

Referenced by StartupXLOG().

◆ TrimMultiXact()

void TrimMultiXact ( void  )

Definition at line 2029 of file multixact.c.

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

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

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

3212 {
3213  XLogRecPtr recptr;
3214  xl_multixact_truncate xlrec;
3215 
3216  xlrec.oldestMultiDB = oldestMultiDB;
3217 
3218  xlrec.startTruncOff = startTruncOff;
3219  xlrec.endTruncOff = endTruncOff;
3220 
3221  xlrec.startTruncMemb = startTruncMemb;
3222  xlrec.endTruncMemb = endTruncMemb;
3223 
3224  XLogBeginInsert();
3225  XLogRegisterData((char *) (&xlrec), SizeOfMultiXactTruncate);
3226  recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
3227  XLogFlush(recptr);
3228 }
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2512
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 3195 of file multixact.c.

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

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

Referenced by ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

◆ ZeroMultiXactMemberPage()

static int ZeroMultiXactMemberPage ( int  pageno,
bool  writeXlog 
)
static

Definition at line 1945 of file multixact.c.

1946 {
1947  int slotno;
1948 
1949  slotno = SimpleLruZeroPage(MultiXactMemberCtl, pageno);
1950 
1951  if (writeXlog)
1953 
1954  return slotno;
1955 }
static void WriteMZeroPageXlogRec(int pageno, uint8 info)
Definition: multixact.c:3195
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 1929 of file multixact.c.

1930 {
1931  int slotno;
1932 
1933  slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
1934 
1935  if (writeXlog)
1937 
1938  return slotno;
1939 }

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

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

◆ OldestMemberMXactId

◆ OldestVisibleMXactId