PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
multixact.c File Reference
#include "postgres.h"
#include "access/multixact.h"
#include "access/slru.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "access/xact.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "funcapi.h"
#include "lib/ilist.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "postmaster/autovacuum.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
Include dependency graph for multixact.c:

Go to the source code of this file.

Data Structures

struct  MultiXactStateData
 
struct  mXactCacheEnt
 
struct  mxtruncinfo
 

Macros

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

Typedefs

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

Functions

static void MultiXactIdSetOldestVisible (void)
 
static void RecordNewMultiXact (MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
 
static MultiXactId GetNewMultiXactId (int nmembers, MultiXactOffset *offset)
 
static int mxactMemberComparator (const void *arg1, const void *arg2)
 
static MultiXactId mXactCacheGetBySet (int nmembers, MultiXactMember *members)
 
static int mXactCacheGetById (MultiXactId multi, MultiXactMember **members)
 
static void mXactCachePut (MultiXactId multi, int nmembers, MultiXactMember *members)
 
static char * mxstatus_to_string (MultiXactStatus status)
 
static int ZeroMultiXactOffsetPage (int pageno, bool writeXlog)
 
static int ZeroMultiXactMemberPage (int pageno, bool writeXlog)
 
static bool MultiXactOffsetPagePrecedes (int page1, int page2)
 
static bool MultiXactMemberPagePrecedes (int page1, int page2)
 
static bool MultiXactOffsetPrecedes (MultiXactOffset offset1, MultiXactOffset offset2)
 
static void ExtendMultiXactOffset (MultiXactId multi)
 
static void ExtendMultiXactMember (MultiXactOffset offset, int nmembers)
 
static bool MultiXactOffsetWouldWrap (MultiXactOffset boundary, MultiXactOffset start, uint32 distance)
 
static bool SetOffsetVacuumLimit (bool is_startup)
 
static bool find_multixact_start (MultiXactId multi, MultiXactOffset *result)
 
static void WriteMZeroPageXlogRec (int pageno, uint8 info)
 
static void WriteMTruncateXlogRec (Oid oldestMultiDB, MultiXactId startOff, MultiXactId endOff, MultiXactOffset startMemb, MultiXactOffset endMemb)
 
MultiXactId MultiXactIdCreate (TransactionId xid1, MultiXactStatus status1, TransactionId xid2, MultiXactStatus status2)
 
MultiXactId MultiXactIdExpand (MultiXactId multi, TransactionId xid, MultiXactStatus status)
 
bool MultiXactIdIsRunning (MultiXactId multi, bool isLockOnly)
 
void MultiXactIdSetOldestMember (void)
 
MultiXactId ReadNextMultiXactId (void)
 
MultiXactId MultiXactIdCreateFromMembers (int nmembers, MultiXactMember *members)
 
int GetMultiXactIdMembers (MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
 
char * mxid_to_string (MultiXactId multi, int nmembers, MultiXactMember *members)
 
void AtEOXact_MultiXact (void)
 
void AtPrepare_MultiXact (void)
 
void PostPrepare_MultiXact (TransactionId xid)
 
void multixact_twophase_recover (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postcommit (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postabort (TransactionId xid, uint16 info, void *recdata, uint32 len)
 
Size MultiXactShmemSize (void)
 
void MultiXactShmemInit (void)
 
void BootStrapMultiXact (void)
 
static void MaybeExtendOffsetSlru (void)
 
void StartupMultiXact (void)
 
void TrimMultiXact (void)
 
void ShutdownMultiXact (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)
 

Variables

static SlruCtlData MultiXactOffsetCtlData
 
static SlruCtlData MultiXactMemberCtlData
 
static MultiXactStateDataMultiXactState
 
static MultiXactIdOldestMemberMXactId
 
static MultiXactIdOldestVisibleMXactId
 
static dlist_head MXactCache = DLIST_STATIC_INIT(MXactCache)
 
static int MXactCacheMembers = 0
 
static MemoryContext MXactContext = NULL
 

Macro Definition Documentation

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

Definition at line 336 of file multixact.c.

Referenced by MultiXactIdExpand().

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

Definition at line 337 of file multixact.c.

Referenced by MultiXactGetCheckptMulti().

#define MAX_CACHE_ENTRIES   256

Definition at line 321 of file multixact.c.

Referenced by mXactCachePut().

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

Definition at line 155 of file multixact.c.

Referenced by ExtendMultiXactMember().

#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)
#define MULTIXACT_FLAGBYTES_PER_GROUP   4

Definition at line 135 of file multixact.c.

#define MULTIXACT_MEMBER_DANGER_THRESHOLD   (MaxMultiXactOffset - MaxMultiXactOffset / 4)

Definition at line 178 of file multixact.c.

Referenced by MultiXactMemberFreezeThreshold().

#define MULTIXACT_MEMBER_SAFE_THRESHOLD   (MaxMultiXactOffset / 2)
#define MULTIXACT_MEMBERGROUP_SIZE   (sizeof(TransactionId) * MULTIXACT_MEMBERS_PER_MEMBERGROUP + MULTIXACT_FLAGBYTES_PER_GROUP)

Definition at line 139 of file multixact.c.

#define MULTIXACT_MEMBERGROUPS_PER_PAGE   (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE)

Definition at line 141 of file multixact.c.

#define MULTIXACT_MEMBERS_PER_MEMBERGROUP   (MULTIXACT_FLAGBYTES_PER_GROUP * MXACT_MEMBER_FLAGS_PER_BYTE)

Definition at line 136 of file multixact.c.

#define MULTIXACT_OFFSETS_PER_PAGE   (BLCKSZ / sizeof(MultiXactOffset))

Definition at line 109 of file multixact.c.

Referenced by MultiXactOffsetPagePrecedes(), and TruncateMultiXact().

#define MultiXactIdToOffsetEntry (   xid)    ((xid) % (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE)
#define MultiXactIdToOffsetSegment (   xid)    (MultiXactIdToOffsetPage(xid) / SLRU_PAGES_PER_SEGMENT)

Definition at line 115 of file multixact.c.

Referenced by multixact_redo(), and TruncateMultiXact().

#define MXACT_MEMBER_BITS_PER_XACT   8

Definition at line 130 of file multixact.c.

Referenced by RecordNewMultiXact().

#define MXACT_MEMBER_FLAGS_PER_BYTE   1

Definition at line 131 of file multixact.c.

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

Definition at line 132 of file multixact.c.

Referenced by GetMultiXactIdMembers().

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

Definition at line 167 of file multixact.c.

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

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

Definition at line 163 of file multixact.c.

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

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

Definition at line 172 of file multixact.c.

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

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

Definition at line 160 of file multixact.c.

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

#define OFFSET_WARN_SEGMENTS   20

Referenced by GetNewMultiXactId().

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

Definition at line 181 of file multixact.c.

Referenced by PerformOffsetsTruncation().

#define SHARED_MULTIXACT_STATE_SIZE
Value:
add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
Size mul_size(Size s1, Size s2)
Definition: shmem.c:492
Size add_size(Size s1, Size s2)
Definition: shmem.c:475
TransactionId MultiXactId
Definition: c.h:407
#define MaxOldestSlot
Definition: multixact.c:288
#define offsetof(type, field)
Definition: c.h:555

Referenced by MultiXactShmemInit(), and MultiXactShmemSize().

Typedef Documentation

Function Documentation

void AtEOXact_MultiXact ( void  )

Definition at line 1662 of file multixact.c.

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

Referenced by AbortTransaction(), and CommitTransaction().

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

Definition at line 1691 of file multixact.c.

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

Referenced by PrepareTransaction().

1692 {
1693  MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId];
1694 
1695  if (MultiXactIdIsValid(myOldestMember))
1697  &myOldestMember, sizeof(MultiXactId));
1698 }
BackendId MyBackendId
Definition: globals.c:73
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1164
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
#define TWOPHASE_RM_MULTIXACT_ID
Definition: twophase_rmgr.h:27
TransactionId MultiXactId
Definition: c.h:407
void BootStrapMultiXact ( void  )

Definition at line 1866 of file multixact.c.

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

Referenced by BootStrapXLOG().

1867 {
1868  int slotno;
1869 
1870  LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
1871 
1872  /* Create and zero the first page of the offsets log */
1873  slotno = ZeroMultiXactOffsetPage(0, false);
1874 
1875  /* Make sure it's written out */
1877  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
1878 
1879  LWLockRelease(MultiXactOffsetControlLock);
1880 
1881  LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
1882 
1883  /* Create and zero the first page of the members log */
1884  slotno = ZeroMultiXactMemberPage(0, false);
1885 
1886  /* Make sure it's written out */
1888  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
1889 
1890  LWLockRelease(MultiXactMemberControlLock);
1891 }
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1903
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:574
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:675
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1919
#define MultiXactMemberCtl
Definition: multixact.c:191
void CheckPointMultiXact ( void  )

Definition at line 2140 of file multixact.c.

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruFlush().

Referenced by CheckPointGuts().

2141 {
2142  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2143 
2144  /* Flush dirty MultiXact pages to disk */
2147 
2148  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2149 }
void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1100
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define MultiXactMemberCtl
Definition: multixact.c:191
static void ExtendMultiXactMember ( MultiXactOffset  offset,
int  nmembers 
)
static

Definition at line 2419 of file multixact.c.

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

Referenced by GetNewMultiXactId().

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

Definition at line 2389 of file multixact.c.

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

Referenced by GetNewMultiXactId().

2390 {
2391  int pageno;
2392 
2393  /*
2394  * No work except at first MultiXactId of a page. But beware: just after
2395  * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2396  */
2397  if (MultiXactIdToOffsetEntry(multi) != 0 &&
2398  multi != FirstMultiXactId)
2399  return;
2400 
2401  pageno = MultiXactIdToOffsetPage(multi);
2402 
2403  LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
2404 
2405  /* Zero the page and make an XLOG entry about it */
2406  ZeroMultiXactOffsetPage(pageno, true);
2407 
2408  LWLockRelease(MultiXactOffsetControlLock);
2409 }
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1903
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
#define FirstMultiXactId
Definition: multixact.h:24
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
static bool find_multixact_start ( MultiXactId  multi,
MultiXactOffset result 
)
static

Definition at line 2719 of file multixact.c.

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

Referenced by SetOffsetVacuumLimit(), and TruncateMultiXact().

2720 {
2721  MultiXactOffset offset;
2722  int pageno;
2723  int entryno;
2724  int slotno;
2725  MultiXactOffset *offptr;
2726 
2728 
2729  pageno = MultiXactIdToOffsetPage(multi);
2730  entryno = MultiXactIdToOffsetEntry(multi);
2731 
2732  /*
2733  * Flush out dirty data, so PhysicalPageExists can work correctly.
2734  * SimpleLruFlush() is a pretty big hammer for that. Alternatively we
2735  * could add a in-memory version of page exists, but find_multixact_start
2736  * is called infrequently, and it doesn't seem bad to flush buffers to
2737  * disk before truncation.
2738  */
2741 
2743  return false;
2744 
2745  /* lock is acquired by SimpleLruReadPage_ReadOnly */
2746  slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
2747  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2748  offptr += entryno;
2749  offset = *offptr;
2750  LWLockRelease(MultiXactOffsetControlLock);
2751 
2752  *result = offset;
2753  return true;
2754 }
uint32 MultiXactOffset
Definition: c.h:409
return result
Definition: formatting.c:1633
void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1100
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno)
Definition: slru.c:586
#define MultiXactOffsetCtl
Definition: multixact.c:190
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:463
#define Assert(condition)
Definition: c.h:675
#define MultiXactMemberCtl
Definition: multixact.c:191
int GetMultiXactIdMembers ( MultiXactId  multi,
MultiXactMember **  members,
bool  from_pgupgrade,
bool  onlyLock 
)

Definition at line 1202 of file multixact.c.

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

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

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

Definition at line 935 of file multixact.c.

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

Referenced by MultiXactIdCreateFromMembers().

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

Definition at line 2491 of file multixact.c.

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

Referenced by AddNewRelationTuple(), ExecuteTruncate(), vac_update_datfrozenxid(), and vacuum_set_xid_limits().

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

Definition at line 1947 of file multixact.c.

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

Referenced by MultiXactSetNextMXact().

1948 {
1949  int pageno;
1950 
1952 
1953  LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
1954 
1956  {
1957  int slotno;
1958 
1959  /*
1960  * Fortunately for us, SimpleLruWritePage is already prepared to deal
1961  * with creating a new segment file even if the page we're writing is
1962  * not the first in it, so this is enough.
1963  */
1964  slotno = ZeroMultiXactOffsetPage(pageno, false);
1966  }
1967 
1968  LWLockRelease(MultiXactOffsetControlLock);
1969 }
MultiXactId nextMXact
Definition: multixact.c:203
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1903
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno)
Definition: slru.c:586
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:574
#define MultiXactOffsetCtl
Definition: multixact.c:190
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
void multixact_redo ( XLogReaderState record)

Definition at line 3217 of file multixact.c.

References 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, VariableCacheData::nextXid, xl_multixact_create::nmembers, xl_multixact_truncate::oldestMultiDB, PANIC, PerformMembersTruncation(), PerformOffsetsTruncation(), RecordNewMultiXact(), SetMultiXactIdLimit(), ShmemVariableCache, SimpleLruWritePage(), SizeOfMultiXactTruncate, xl_multixact_truncate::startTruncMemb, xl_multixact_truncate::startTruncOff, TransactionIdAdvance, TransactionIdFollowsOrEquals(), 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().

3218 {
3219  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3220 
3221  /* Backup blocks are not used in multixact records */
3222  Assert(!XLogRecHasAnyBlockRefs(record));
3223 
3224  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3225  {
3226  int pageno;
3227  int slotno;
3228 
3229  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3230 
3231  LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
3232 
3233  slotno = ZeroMultiXactOffsetPage(pageno, false);
3235  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3236 
3237  LWLockRelease(MultiXactOffsetControlLock);
3238  }
3239  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3240  {
3241  int pageno;
3242  int slotno;
3243 
3244  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3245 
3246  LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
3247 
3248  slotno = ZeroMultiXactMemberPage(pageno, false);
3250  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3251 
3252  LWLockRelease(MultiXactMemberControlLock);
3253  }
3254  else if (info == XLOG_MULTIXACT_CREATE_ID)
3255  {
3256  xl_multixact_create *xlrec =
3257  (xl_multixact_create *) XLogRecGetData(record);
3258  TransactionId max_xid;
3259  int i;
3260 
3261  /* Store the data back into the SLRU files */
3262  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3263  xlrec->members);
3264 
3265  /* Make sure nextMXact/nextOffset are beyond what this record has */
3266  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3267  xlrec->moff + xlrec->nmembers);
3268 
3269  /*
3270  * Make sure nextXid is beyond any XID mentioned in the record. This
3271  * should be unnecessary, since any XID found here ought to have other
3272  * evidence in the XLOG, but let's be safe.
3273  */
3274  max_xid = XLogRecGetXid(record);
3275  for (i = 0; i < xlrec->nmembers; i++)
3276  {
3277  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3278  max_xid = xlrec->members[i].xid;
3279  }
3280 
3281  /*
3282  * We don't expect anyone else to modify nextXid, hence startup
3283  * process doesn't need to hold a lock while checking this. We still
3284  * acquire the lock to modify it, though.
3285  */
3286  if (TransactionIdFollowsOrEquals(max_xid,
3288  {
3289  LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
3290  ShmemVariableCache->nextXid = max_xid;
3292  LWLockRelease(XidGenLock);
3293  }
3294  }
3295  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3296  {
3297  xl_multixact_truncate xlrec;
3298  int pageno;
3299 
3300  memcpy(&xlrec, XLogRecGetData(record),
3302 
3303  elog(DEBUG1, "replaying multixact truncation: "
3304  "offsets [%u, %u), offsets segments [%x, %x), "
3305  "members [%u, %u), members segments [%x, %x)",
3306  xlrec.startTruncOff, xlrec.endTruncOff,
3309  xlrec.startTruncMemb, xlrec.endTruncMemb,
3312 
3313  /* should not be required, but more than cheap enough */
3314  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3315 
3316  /*
3317  * Advance the horizon values, so they're current at the end of
3318  * recovery.
3319  */
3320  SetMultiXactIdLimit(xlrec.endTruncOff, xlrec.oldestMultiDB, false);
3321 
3323 
3324  /*
3325  * During XLOG replay, latest_page_number isn't necessarily set up
3326  * yet; insert a suitable value to bypass the sanity test in
3327  * SimpleLruTruncate.
3328  */
3329  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3330  MultiXactOffsetCtl->shared->latest_page_number = pageno;
3332 
3333  LWLockRelease(MultiXactTruncationLock);
3334  }
3335  else
3336  elog(PANIC, "multixact_redo: unknown op code %u", info);
3337 }
#define TransactionIdAdvance(dest)
Definition: transam.h:48
#define DEBUG1
Definition: elog.h:25
uint32 TransactionId
Definition: c.h:397
static int ZeroMultiXactOffsetPage(int pageno, bool writeXlog)
Definition: multixact.c:1903
bool TransactionIdFollowsOrEquals(TransactionId id1, TransactionId id2)
Definition: transam.c:349
unsigned char uint8
Definition: c.h:266
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:72
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2347
#define PANIC
Definition: elog.h:53
#define SizeOfMultiXactTruncate
Definition: multixact.h:99
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.h:81
#define XLogRecGetData(decoder)
Definition: xlogreader.h:220
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:73
TransactionId xid
Definition: multixact.h:61
TransactionId nextXid
Definition: transam.h:117
MultiXactOffset moff
Definition: multixact.h:79
#define MultiXactIdToOffsetSegment(xid)
Definition: multixact.c:115
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2880
VariableCache ShmemVariableCache
Definition: varsup.c:34
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:574
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:216
bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition: transam.c:300
MultiXactOffset endTruncMemb
Definition: multixact.h:96
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define XLogRecGetXid(decoder)
Definition: xlogreader.h:218
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:71
MultiXactOffset startTruncMemb
Definition: multixact.h:95
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2194
MultiXactId mid
Definition: multixact.h:78
#define Assert(condition)
Definition: c.h:675
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:74
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:160
MultiXactId startTruncOff
Definition: multixact.h:91
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1919
int i
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:222
#define elog
Definition: elog.h:219
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:841
MultiXactId endTruncOff
Definition: multixact.h:92
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:2908
#define MultiXactMemberCtl
Definition: multixact.c:191
void multixact_twophase_postabort ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 1791 of file multixact.c.

References multixact_twophase_postcommit().

1793 {
1794  multixact_twophase_postcommit(xid, info, recdata, len);
1795 }
void multixact_twophase_postcommit(TransactionId xid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1776
void multixact_twophase_postcommit ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 1776 of file multixact.c.

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

Referenced by multixact_twophase_postabort().

1778 {
1779  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid);
1780 
1781  Assert(len == sizeof(MultiXactId));
1782 
1783  OldestMemberMXactId[dummyBackendId] = InvalidMultiXactId;
1784 }
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
BackendId TwoPhaseGetDummyBackendId(TransactionId xid)
Definition: twophase.c:856
int BackendId
Definition: backendid.h:21
#define InvalidMultiXactId
Definition: multixact.h:23
TransactionId MultiXactId
Definition: c.h:407
#define Assert(condition)
Definition: c.h:675
void multixact_twophase_recover ( TransactionId  xid,
uint16  info,
void *  recdata,
uint32  len 
)

Definition at line 1755 of file multixact.c.

References Assert, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().

1757 {
1758  BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid);
1759  MultiXactId oldestMember;
1760 
1761  /*
1762  * Get the oldest member XID from the state file record, and set it in the
1763  * OldestMemberMXactId slot reserved for this prepared transaction.
1764  */
1765  Assert(len == sizeof(MultiXactId));
1766  oldestMember = *((MultiXactId *) recdata);
1767 
1768  OldestMemberMXactId[dummyBackendId] = oldestMember;
1769 }
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
BackendId TwoPhaseGetDummyBackendId(TransactionId xid)
Definition: twophase.c:856
int BackendId
Definition: backendid.h:21
TransactionId MultiXactId
Definition: c.h:407
#define Assert(condition)
Definition: c.h:675
void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2347 of file multixact.c.

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

Referenced by multixact_redo(), and xlog_redo().

2349 {
2350  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2352  {
2353  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2354  MultiXactState->nextMXact = minMulti;
2355  }
2356  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2357  {
2358  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2359  minMultiOffset);
2360  MultiXactState->nextOffset = minMultiOffset;
2361  }
2362  LWLockRelease(MultiXactGenLock);
2363 }
MultiXactId nextMXact
Definition: multixact.c:203
MultiXactOffset nextOffset
Definition: multixact.c:206
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
#define DEBUG2
Definition: elog.h:24
#define debug_elog3(a, b, c)
Definition: multixact.c:334
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3140
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3166
void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2372 of file multixact.c.

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

Referenced by xlog_redo().

2373 {
2374  Assert(InRecovery);
2375 
2377  SetMultiXactIdLimit(oldestMulti, oldestMultiDB, false);
2378 }
bool InRecovery
Definition: xlog.c:192
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
MultiXactId oldestMultiXactId
Definition: multixact.c:216
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid, bool is_startup)
Definition: multixact.c:2194
#define Assert(condition)
Definition: c.h:675
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3140
void MultiXactGetCheckptMulti ( bool  is_shutdown,
MultiXactId nextMulti,
MultiXactOffset nextMultiOffset,
MultiXactId oldestMulti,
Oid oldestMultiDB 
)

Definition at line 2118 of file multixact.c.

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

Referenced by CreateCheckPoint().

2123 {
2124  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2125  *nextMulti = MultiXactState->nextMXact;
2126  *nextMultiOffset = MultiXactState->nextOffset;
2127  *oldestMulti = MultiXactState->oldestMultiXactId;
2128  *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2129  LWLockRelease(MultiXactGenLock);
2130 
2132  "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u",
2133  *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2134 }
MultiXactId nextMXact
Definition: multixact.c:203
MultiXactOffset nextOffset
Definition: multixact.c:206
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
MultiXactId oldestMultiXactId
Definition: multixact.c:216
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:337
#define DEBUG2
Definition: elog.h:24
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
MultiXactId MultiXactIdCreate ( TransactionId  xid1,
MultiXactStatus  status1,
TransactionId  xid2,
MultiXactStatus  status2 
)

Definition at line 384 of file multixact.c.

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

Referenced by compute_new_xmax_infomask().

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

Definition at line 746 of file multixact.c.

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

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

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

Definition at line 437 of file multixact.c.

References Assert, AssertArg, DEBUG2, debug_elog3, debug_elog4, debug_elog5, GetMultiXactIdMembers(), i, ISUPDATE_from_mxstatus, 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().

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

Definition at line 549 of file multixact.c.

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

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

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

Definition at line 3154 of file multixact.c.

Referenced by lazy_vacuum_rel(), and TruncateMultiXact().

3155 {
3156  int32 diff = (int32) (multi1 - multi2);
3157 
3158  return (diff <= 0);
3159 }
signed int int32
Definition: c.h:256
void MultiXactIdSetOldestMember ( void  )

Definition at line 623 of file multixact.c.

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

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

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

Definition at line 680 of file multixact.c.

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

Referenced by GetMultiXactIdMembers().

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

Definition at line 2817 of file multixact.c.

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

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

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

Definition at line 3122 of file multixact.c.

References MULTIXACT_MEMBERS_PER_PAGE, and MultiXactOffsetPrecedes().

Referenced by MultiXactShmemInit().

3123 {
3124  MultiXactOffset offset1;
3125  MultiXactOffset offset2;
3126 
3127  offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;
3128  offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;
3129 
3130  return MultiXactOffsetPrecedes(offset1, offset2);
3131 }
uint32 MultiXactOffset
Definition: c.h:409
#define MULTIXACT_MEMBERS_PER_PAGE
Definition: multixact.c:142
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3166
static bool MultiXactOffsetPagePrecedes ( int  page1,
int  page2 
)
static

Definition at line 3104 of file multixact.c.

References FirstMultiXactId, MULTIXACT_OFFSETS_PER_PAGE, and MultiXactIdPrecedes().

Referenced by MultiXactShmemInit().

3105 {
3106  MultiXactId multi1;
3107  MultiXactId multi2;
3108 
3109  multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
3110  multi1 += FirstMultiXactId;
3111  multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
3112  multi2 += FirstMultiXactId;
3113 
3114  return MultiXactIdPrecedes(multi1, multi2);
3115 }
#define FirstMultiXactId
Definition: multixact.h:24
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109
TransactionId MultiXactId
Definition: c.h:407
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3140
static bool MultiXactOffsetPrecedes ( MultiXactOffset  offset1,
MultiXactOffset  offset2 
)
static

Definition at line 3166 of file multixact.c.

Referenced by MultiXactAdvanceNextMXact(), and MultiXactMemberPagePrecedes().

3167 {
3168  int32 diff = (int32) (offset1 - offset2);
3169 
3170  return (diff < 0);
3171 }
signed int int32
Definition: c.h:256
static bool MultiXactOffsetWouldWrap ( MultiXactOffset  boundary,
MultiXactOffset  start,
uint32  distance 
)
static

Definition at line 2671 of file multixact.c.

Referenced by GetNewMultiXactId().

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

Definition at line 2160 of file multixact.c.

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

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

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

Definition at line 1820 of file multixact.c.

References Assert, DEBUG2, debug_elog2, IsUnderPostmaster, LWTRANCHE_MXACTMEMBER_BUFFERS, LWTRANCHE_MXACTOFFSET_BUFFERS, MaxOldestSlot, MemSet, MultiXactMemberCtl, MultiXactMemberPagePrecedes(), MultiXactOffsetCtl, MultiXactOffsetPagePrecedes(), NUM_MXACTMEMBER_BUFFERS, NUM_MXACTOFFSET_BUFFERS, OldestMemberMXactId, OldestVisibleMXactId, MultiXactStateData::perBackendXactIds, SHARED_MULTIXACT_STATE_SIZE, ShmemInitStruct(), and SimpleLruInit().

Referenced by CreateSharedMemoryAndSemaphores().

1821 {
1822  bool found;
1823 
1824  debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1825 
1828 
1830  "multixact_offset", NUM_MXACTOFFSET_BUFFERS, 0,
1831  MultiXactOffsetControlLock, "pg_multixact/offsets",
1834  "multixact_member", NUM_MXACTMEMBER_BUFFERS, 0,
1835  MultiXactMemberControlLock, "pg_multixact/members",
1837 
1838  /* Initialize our shared state struct */
1839  MultiXactState = ShmemInitStruct("Shared MultiXact State",
1841  &found);
1842  if (!IsUnderPostmaster)
1843  {
1844  Assert(!found);
1845 
1846  /* Make sure we zero out the per-backend state */
1848  }
1849  else
1850  Assert(found);
1851 
1852  /*
1853  * Set up array pointers. Note that perBackendXactIds[0] is wasted space
1854  * since we only use indexes 1..MaxOldestSlot in each array.
1855  */
1858 }
#define NUM_MXACTMEMBER_BUFFERS
Definition: multixact.h:33
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.c:281
static bool MultiXactOffsetPagePrecedes(int page1, int page2)
Definition: multixact.c:3104
#define MemSet(start, val, len)
Definition: c.h:857
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
#define NUM_MXACTOFFSET_BUFFERS
Definition: multixact.h:32
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition: shmem.c:372
#define DEBUG2
Definition: elog.h:24
bool IsUnderPostmaster
Definition: globals.c:101
#define debug_elog2(a, b)
Definition: multixact.c:333
static bool MultiXactMemberPagePrecedes(int page1, int page2)
Definition: multixact.c:3122
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:675
#define MaxOldestSlot
Definition: multixact.c:288
#define MultiXactMemberCtl
Definition: multixact.c:191
#define SHARED_MULTIXACT_STATE_SIZE
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, LWLock *ctllock, const char *subdir, int tranche_id)
Definition: slru.c:165
Size MultiXactShmemSize ( void  )

Definition at line 1803 of file multixact.c.

References add_size(), NUM_MXACTMEMBER_BUFFERS, NUM_MXACTOFFSET_BUFFERS, SHARED_MULTIXACT_STATE_SIZE, and SimpleLruShmemSize().

Referenced by CreateSharedMemoryAndSemaphores().

1804 {
1805  Size size;
1806 
1807  /* We need 2*MaxOldestSlot + 1 perBackendXactIds[] entries */
1808 #define SHARED_MULTIXACT_STATE_SIZE \
1809  add_size(offsetof(MultiXactStateData, perBackendXactIds) + sizeof(MultiXactId), \
1810  mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1811 
1815 
1816  return size;
1817 }
#define NUM_MXACTMEMBER_BUFFERS
Definition: multixact.h:33
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition: slru.c:145
#define NUM_MXACTOFFSET_BUFFERS
Definition: multixact.h:32
Size add_size(Size s1, Size s2)
Definition: shmem.c:475
size_t Size
Definition: c.h:356
#define SHARED_MULTIXACT_STATE_SIZE
static int mXactCacheGetById ( MultiXactId  multi,
MultiXactMember **  members 
)
static

Definition at line 1515 of file multixact.c.

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

Referenced by GetMultiXactIdMembers().

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

Definition at line 1473 of file multixact.c.

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

Referenced by MultiXactIdCreateFromMembers().

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

Definition at line 1561 of file multixact.c.

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

Referenced by GetMultiXactIdMembers(), and MultiXactIdCreateFromMembers().

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

Definition at line 1443 of file multixact.c.

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

Referenced by mXactCacheGetBySet(), and mXactCachePut().

1444 {
1445  MultiXactMember member1 = *(const MultiXactMember *) arg1;
1446  MultiXactMember member2 = *(const MultiXactMember *) arg2;
1447 
1448  if (member1.xid > member2.xid)
1449  return 1;
1450  if (member1.xid < member2.xid)
1451  return -1;
1452  if (member1.status > member2.status)
1453  return 1;
1454  if (member1.status < member2.status)
1455  return -1;
1456  return 0;
1457 }
TransactionId xid
Definition: multixact.h:61
MultiXactStatus status
Definition: multixact.h:62
char* mxid_to_string ( MultiXactId  multi,
int  nmembers,
MultiXactMember members 
)

Definition at line 1631 of file multixact.c.

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

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

1632 {
1633  static char *str = NULL;
1635  int i;
1636 
1637  if (str != NULL)
1638  pfree(str);
1639 
1640  initStringInfo(&buf);
1641 
1642  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1643  mxstatus_to_string(members[0].status));
1644 
1645  for (i = 1; i < nmembers; i++)
1646  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1647  mxstatus_to_string(members[i].status));
1648 
1649  appendStringInfoChar(&buf, ']');
1651  pfree(buf.data);
1652  return str;
1653 }
void pfree(void *pointer)
Definition: mcxt.c:950
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
static char * buf
Definition: pg_test_fsync.c:66
MemoryContext TopMemoryContext
Definition: mcxt.c:43
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void initStringInfo(StringInfo str)
Definition: stringinfo.c:46
#define NULL
Definition: c.h:229
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1064
int i
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1608
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
static char * mxstatus_to_string ( MultiXactStatus  status)
static

Definition at line 1608 of file multixact.c.

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

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

1609 {
1610  switch (status)
1611  {
1613  return "keysh";
1615  return "sh";
1617  return "fornokeyupd";
1619  return "forupd";
1621  return "nokeyupd";
1622  case MultiXactStatusUpdate:
1623  return "upd";
1624  default:
1625  elog(ERROR, "unrecognized multixact status %d", status);
1626  return "";
1627  }
1628 }
#define ERROR
Definition: elog.h:43
#define elog
Definition: elog.h:219
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
static void PerformMembersTruncation ( MultiXactOffset  oldestOffset,
MultiXactOffset  newOldestOffset 
)
static

Definition at line 2880 of file multixact.c.

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

Referenced by multixact_redo(), and TruncateMultiXact().

2881 {
2882  const int maxsegment = MXOffsetToMemberSegment(MaxMultiXactOffset);
2883  int startsegment = MXOffsetToMemberSegment(oldestOffset);
2884  int endsegment = MXOffsetToMemberSegment(newOldestOffset);
2885  int segment = startsegment;
2886 
2887  /*
2888  * Delete all the segments but the last one. The last segment can still
2889  * contain, possibly partially, valid data.
2890  */
2891  while (segment != endsegment)
2892  {
2893  elog(DEBUG2, "truncating multixact members segment %x", segment);
2895 
2896  /* move to next segment, handling wraparound correctly */
2897  if (segment == maxsegment)
2898  segment = 0;
2899  else
2900  segment += 1;
2901  }
2902 }
#define MaxMultiXactOffset
Definition: multixact.h:29
#define DEBUG2
Definition: elog.h:24
#define MXOffsetToMemberSegment(xid)
Definition: multixact.c:160
void SlruDeleteSegment(SlruCtl ctl, int segno)
Definition: slru.c:1258
#define elog
Definition: elog.h:219
#define MultiXactMemberCtl
Definition: multixact.c:191
static void PerformOffsetsTruncation ( MultiXactId  oldestMulti,
MultiXactId  newOldestMulti 
)
static

Definition at line 2908 of file multixact.c.

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

Referenced by multixact_redo(), and TruncateMultiXact().

2909 {
2910  /*
2911  * We step back one multixact to avoid passing a cutoff page that hasn't
2912  * been created yet in the rare case that oldestMulti would be the first
2913  * item on a page and oldestMulti == nextMulti. In that case, if we
2914  * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
2915  * detection.
2916  */
2918  MultiXactIdToOffsetPage(PreviousMultiXactId(newOldestMulti)));
2919 }
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1165
#define PreviousMultiXactId(xid)
Definition: multixact.c:181
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
#define MultiXactOffsetCtl
Definition: multixact.c:190
Datum pg_get_multixact_members ( PG_FUNCTION_ARGS  )

Definition at line 3340 of file multixact.c.

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

3341 {
3342  typedef struct
3343  {
3344  MultiXactMember *members;
3345  int nmembers;
3346  int iter;
3347  } mxact;
3348  MultiXactId mxid = PG_GETARG_UINT32(0);
3349  mxact *multi;
3350  FuncCallContext *funccxt;
3351 
3352  if (mxid < FirstMultiXactId)
3353  ereport(ERROR,
3354  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3355  errmsg("invalid MultiXactId: %u", mxid)));
3356 
3357  if (SRF_IS_FIRSTCALL())
3358  {
3359  MemoryContext oldcxt;
3360  TupleDesc tupdesc;
3361 
3362  funccxt = SRF_FIRSTCALL_INIT();
3363  oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx);
3364 
3365  multi = palloc(sizeof(mxact));
3366  /* no need to allow for old values here */
3367  multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
3368  false);
3369  multi->iter = 0;
3370 
3371  tupdesc = CreateTemplateTupleDesc(2, false);
3372  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "xid",
3373  XIDOID, -1, 0);
3374  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "mode",
3375  TEXTOID, -1, 0);
3376 
3377  funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
3378  funccxt->user_fctx = multi;
3379 
3380  MemoryContextSwitchTo(oldcxt);
3381  }
3382 
3383  funccxt = SRF_PERCALL_SETUP();
3384  multi = (mxact *) funccxt->user_fctx;
3385 
3386  while (multi->iter < multi->nmembers)
3387  {
3388  HeapTuple tuple;
3389  char *values[2];
3390 
3391  values[0] = psprintf("%u", multi->members[multi->iter].xid);
3392  values[1] = mxstatus_to_string(multi->members[multi->iter].status);
3393 
3394  tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
3395 
3396  multi->iter++;
3397  pfree(values[0]);
3398  SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
3399  }
3400 
3401  if (multi->nmembers > 0)
3402  pfree(multi->members);
3403  pfree(multi);
3404 
3405  SRF_RETURN_DONE(funccxt);
3406 }
#define PG_GETARG_UINT32(n)
Definition: fmgr.h:235
#define TEXTOID
Definition: pg_type.h:324
#define SRF_IS_FIRSTCALL()
Definition: funcapi.h:285
char * psprintf(const char *fmt,...)
Definition: psprintf.c:46
static MemoryContext MemoryContextSwitchTo(MemoryContext context)
Definition: palloc.h:109
int errcode(int sqlerrcode)
Definition: elog.c:575
#define XIDOID
Definition: pg_type.h:336
#define SRF_PERCALL_SETUP()
Definition: funcapi.h:289
HeapTuple BuildTupleFromCStrings(AttInMetadata *attinmeta, char **values)
Definition: execTuples.c:1115
#define SRF_RETURN_NEXT(_funcctx, _result)
Definition: funcapi.h:291
void pfree(void *pointer)
Definition: mcxt.c:950
#define ERROR
Definition: elog.h:43
AttInMetadata * attinmeta
Definition: funcapi.h:99
#define FirstMultiXactId
Definition: multixact.h:24
void TupleDescInitEntry(TupleDesc desc, AttrNumber attributeNumber, const char *attributeName, Oid oidtypeid, int32 typmod, int attdim)
Definition: tupdesc.c:497
#define ereport(elevel, rest)
Definition: elog.h:122
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:1068
TransactionId MultiXactId
Definition: c.h:407
MemoryContext multi_call_memory_ctx
Definition: funcapi.h:109
#define HeapTupleGetDatum(tuple)
Definition: funcapi.h:222
TupleDesc CreateTemplateTupleDesc(int natts, bool hasoid)
Definition: tupdesc.c:41
static Datum values[MAXATTR]
Definition: bootstrap.c:163
void * user_fctx
Definition: funcapi.h:90
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1608
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool onlyLock)
Definition: multixact.c:1202
int16 AttrNumber
Definition: attnum.h:21
#define SRF_RETURN_DONE(_funcctx)
Definition: funcapi.h:309
#define SRF_FIRSTCALL_INIT()
Definition: funcapi.h:287
void PostPrepare_MultiXact ( TransactionId  xid)

Definition at line 1705 of file multixact.c.

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

Referenced by PrepareTransaction().

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

Definition at line 2761 of file multixact.c.

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

Referenced by MultiXactMemberFreezeThreshold().

2762 {
2763  MultiXactOffset nextOffset;
2764  MultiXactOffset oldestOffset;
2765  MultiXactId oldestMultiXactId;
2766  MultiXactId nextMultiXactId;
2767  bool oldestOffsetKnown;
2768 
2769  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2770  nextOffset = MultiXactState->nextOffset;
2771  oldestMultiXactId = MultiXactState->oldestMultiXactId;
2772  nextMultiXactId = MultiXactState->nextMXact;
2773  oldestOffset = MultiXactState->oldestOffset;
2774  oldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2775  LWLockRelease(MultiXactGenLock);
2776 
2777  if (!oldestOffsetKnown)
2778  return false;
2779 
2780  *members = nextOffset - oldestOffset;
2781  *multixacts = nextMultiXactId - oldestMultiXactId;
2782  return true;
2783 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:409
MultiXactOffset nextOffset
Definition: multixact.c:206
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
MultiXactId oldestMultiXactId
Definition: multixact.c:216
MultiXactOffset oldestOffset
Definition: multixact.c:224
TransactionId MultiXactId
Definition: c.h:407
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
MultiXactId ReadNextMultiXactId ( void  )

Definition at line 721 of file multixact.c.

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

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

722 {
723  MultiXactId mxid;
724 
725  /* XXX we could presumably do this without a lock. */
726  LWLockAcquire(MultiXactGenLock, LW_SHARED);
727  mxid = MultiXactState->nextMXact;
728  LWLockRelease(MultiXactGenLock);
729 
730  if (mxid < FirstMultiXactId)
731  mxid = FirstMultiXactId;
732 
733  return mxid;
734 }
MultiXactId nextMXact
Definition: multixact.c:203
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
#define FirstMultiXactId
Definition: multixact.h:24
TransactionId MultiXactId
Definition: c.h:407
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
static void RecordNewMultiXact ( MultiXactId  multi,
MultiXactOffset  offset,
int  nmembers,
MultiXactMember members 
)
static

Definition at line 841 of file multixact.c.

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

Referenced by multixact_redo(), and MultiXactIdCreateFromMembers().

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

Definition at line 2194 of file multixact.c.

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

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

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

Definition at line 2544 of file multixact.c.

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

Referenced by SetMultiXactIdLimit().

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

Definition at line 2105 of file multixact.c.

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruFlush().

Referenced by ShutdownXLOG().

2106 {
2107  /* Flush dirty MultiXact pages to disk */
2108  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(false);
2111  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(false);
2112 }
void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1100
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define MultiXactMemberCtl
Definition: multixact.c:191
static bool SlruScanDirCbFindEarliest ( SlruCtl  ctl,
char *  filename,
int  segpage,
void *  data 
)
static

Definition at line 2857 of file multixact.c.

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

Referenced by TruncateMultiXact().

2858 {
2859  mxtruncinfo *trunc = (mxtruncinfo *) data;
2860 
2861  if (trunc->earliestExistingPage == -1 ||
2862  ctl->PagePrecedes(segpage, trunc->earliestExistingPage))
2863  {
2864  trunc->earliestExistingPage = segpage;
2865  }
2866 
2867  return false; /* keep going */
2868 }
bool(* PagePrecedes)(int, int)
Definition: slru.h:132
int earliestExistingPage
Definition: multixact.c:2849
void StartupMultiXact ( void  )

Definition at line 1980 of file multixact.c.

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

Referenced by StartupXLOG().

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

Definition at line 2003 of file multixact.c.

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

Referenced by StartupXLOG().

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

Definition at line 2933 of file multixact.c.

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

Referenced by vac_truncate_clog().

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

Definition at line 3192 of file multixact.c.

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

Referenced by TruncateMultiXact().

3195 {
3196  XLogRecPtr recptr;
3197  xl_multixact_truncate xlrec;
3198 
3199  xlrec.oldestMultiDB = oldestMultiDB;
3200 
3201  xlrec.startTruncOff = startTruncOff;
3202  xlrec.endTruncOff = endTruncOff;
3203 
3204  xlrec.startTruncMemb = startTruncMemb;
3205  xlrec.endTruncMemb = endTruncMemb;
3206 
3207  XLogBeginInsert();
3208  XLogRegisterData((char *) (&xlrec), SizeOfMultiXactTruncate);
3209  recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
3210  XLogFlush(recptr);
3211 }
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2757
#define SizeOfMultiXactTruncate
Definition: multixact.h:99
MultiXactOffset endTruncMemb
Definition: multixact.h:96
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
MultiXactOffset startTruncMemb
Definition: multixact.h:95
uint64 XLogRecPtr
Definition: xlogdefs.h:21
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:74
MultiXactId startTruncOff
Definition: multixact.h:91
MultiXactId endTruncOff
Definition: multixact.h:92
void XLogBeginInsert(void)
Definition: xloginsert.c:120
static void WriteMZeroPageXlogRec ( int  pageno,
uint8  info 
)
static

Definition at line 3178 of file multixact.c.

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

Referenced by ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

3179 {
3180  XLogBeginInsert();
3181  XLogRegisterData((char *) (&pageno), sizeof(int));
3182  (void) XLogInsert(RM_MULTIXACT_ID, info);
3183 }
void XLogRegisterData(char *data, int len)
Definition: xloginsert.c:323
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition: xloginsert.c:415
void XLogBeginInsert(void)
Definition: xloginsert.c:120
static int ZeroMultiXactMemberPage ( int  pageno,
bool  writeXlog 
)
static

Definition at line 1919 of file multixact.c.

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

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

1920 {
1921  int slotno;
1922 
1923  slotno = SimpleLruZeroPage(MultiXactMemberCtl, pageno);
1924 
1925  if (writeXlog)
1927 
1928  return slotno;
1929 }
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:72
static void WriteMZeroPageXlogRec(int pageno, uint8 info)
Definition: multixact.c:3178
#define MultiXactMemberCtl
Definition: multixact.c:191
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:259
static int ZeroMultiXactOffsetPage ( int  pageno,
bool  writeXlog 
)
static

Definition at line 1903 of file multixact.c.

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

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

1904 {
1905  int slotno;
1906 
1907  slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno);
1908 
1909  if (writeXlog)
1911 
1912  return slotno;
1913 }
static void WriteMZeroPageXlogRec(int pageno, uint8 info)
Definition: multixact.c:3178
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:71
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:259

Variable Documentation

SlruCtlData MultiXactMemberCtlData
static

Definition at line 188 of file multixact.c.

SlruCtlData MultiXactOffsetCtlData
static

Definition at line 187 of file multixact.c.

MultiXactStateData* MultiXactState
static

Definition at line 291 of file multixact.c.

dlist_head MXactCache = DLIST_STATIC_INIT(MXactCache)
static

Definition at line 322 of file multixact.c.

int MXactCacheMembers = 0
static

Definition at line 323 of file multixact.c.

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

MemoryContext MXactContext = NULL
static

Definition at line 324 of file multixact.c.