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 (void)
 
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)
 
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:393
#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:393
#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:393
#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:403
#define MaxOldestSlot
Definition: multixact.c:288
#define offsetof(type, field)
Definition: c.h:550

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:72
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:226
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:72
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition: twophase.c:1121
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
#define TWOPHASE_RM_MULTIXACT_ID
Definition: twophase_rmgr.h:27
TransactionId MultiXactId
Definition: c.h:403
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:1714
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:573
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:670
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
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:1090
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define MultiXactMemberCtl
Definition: multixact.c:191
static void ExtendMultiXactMember ( MultiXactOffset  offset,
int  nmembers 
)
static

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

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

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

Referenced by GetNewMultiXactId().

2386 {
2387  int pageno;
2388 
2389  /*
2390  * No work except at first MultiXactId of a page. But beware: just after
2391  * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2392  */
2393  if (MultiXactIdToOffsetEntry(multi) != 0 &&
2394  multi != FirstMultiXactId)
2395  return;
2396 
2397  pageno = MultiXactIdToOffsetPage(multi);
2398 
2399  LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
2400 
2401  /* Zero the page and make an XLOG entry about it */
2402  ZeroMultiXactOffsetPage(pageno, true);
2403 
2404  LWLockRelease(MultiXactOffsetControlLock);
2405 }
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:1714
#define FirstMultiXactId
Definition: multixact.h:24
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
static bool find_multixact_start ( MultiXactId  multi,
MultiXactOffset result 
)
static

Definition at line 2714 of file multixact.c.

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

Referenced by SetOffsetVacuumLimit(), and TruncateMultiXact().

2715 {
2716  MultiXactOffset offset;
2717  int pageno;
2718  int entryno;
2719  int slotno;
2720  MultiXactOffset *offptr;
2721 
2723 
2724  pageno = MultiXactIdToOffsetPage(multi);
2725  entryno = MultiXactIdToOffsetEntry(multi);
2726 
2727  /*
2728  * Flush out dirty data, so PhysicalPageExists can work correctly.
2729  * SimpleLruFlush() is a pretty big hammer for that. Alternatively we
2730  * could add a in-memory version of page exists, but find_multixact_start
2731  * is called infrequently, and it doesn't seem bad to flush buffers to
2732  * disk before truncation.
2733  */
2736 
2738  return false;
2739 
2740  /* lock is acquired by SimpleLruReadPage_ReadOnly */
2741  slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, multi);
2742  offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2743  offptr += entryno;
2744  offset = *offptr;
2745  LWLockRelease(MultiXactOffsetControlLock);
2746 
2747  *result = offset;
2748  return true;
2749 }
uint32 MultiXactOffset
Definition: c.h:405
void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1090
#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:1714
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno)
Definition: slru.c:585
#define MultiXactOffsetCtl
Definition: multixact.c:190
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int pageno, TransactionId xid)
Definition: slru.c:462
#define Assert(condition)
Definition: c.h:670
#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:72
#define MXOffsetToFlagsBitShift(xid)
Definition: multixact.c:167
uint32 MultiXactOffset
Definition: c.h:405
uint32 TransactionId
Definition: c.h:393
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:1714
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:370
#define DEBUG2
Definition: elog.h:24
MultiXactStatus status
Definition: multixact.h:62
unsigned int uint32
Definition: c.h:265
#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:403
#define NULL
Definition: c.h:226
#define Assert(condition)
Definition: c.h:670
static void MultiXactIdSetOldestVisible(void)
Definition: multixact.c:680
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
static void mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1561
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3135
void * palloc(Size size)
Definition: mcxt.c:891
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:97
#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(), SendPostmasterSignal(), SLRU_PAGES_PER_SEGMENT, START_CRIT_SECTION, and WARNING.

Referenced by MultiXactIdCreateFromMembers().

936 {
937  MultiXactId result;
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:405
#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:130
int errcode(int sqlerrcode)
Definition: elog.c:575
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
unsigned int Oid
Definition: postgres_ext.h:31
bool RecoveryInProgress(void)
Definition: xlog.c:7825
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
static bool MultiXactOffsetWouldWrap(MultiXactOffset boundary, MultiXactOffset start, uint32 distance)
Definition: multixact.c:2666
#define ERROR
Definition: elog.h:43
MultiXactId multiVacLimit
Definition: multixact.c:228
char * get_database_name(Oid dbid)
Definition: dbcommands.c:2049
#define DEBUG2
Definition: elog.h:24
bool IsUnderPostmaster
Definition: globals.c:100
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:2385
TransactionId MultiXactId
Definition: c.h:403
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:1110
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3135
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:2415
MultiXactId GetOldestMultiXactId ( void  )

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

2488 {
2489  MultiXactId oldestMXact;
2490  MultiXactId nextMXact;
2491  int i;
2492 
2493  /*
2494  * This is the oldest valid value among all the OldestMemberMXactId[] and
2495  * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2496  */
2497  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2498 
2499  /*
2500  * We have to beware of the possibility that nextMXact is in the
2501  * wrapped-around state. We don't fix the counter itself here, but we
2502  * must be sure to use a valid value in our calculation.
2503  */
2504  nextMXact = MultiXactState->nextMXact;
2505  if (nextMXact < FirstMultiXactId)
2506  nextMXact = FirstMultiXactId;
2507 
2508  oldestMXact = nextMXact;
2509  for (i = 1; i <= MaxOldestSlot; i++)
2510  {
2511  MultiXactId thisoldest;
2512 
2513  thisoldest = OldestMemberMXactId[i];
2514  if (MultiXactIdIsValid(thisoldest) &&
2515  MultiXactIdPrecedes(thisoldest, oldestMXact))
2516  oldestMXact = thisoldest;
2517  thisoldest = OldestVisibleMXactId[i];
2518  if (MultiXactIdIsValid(thisoldest) &&
2519  MultiXactIdPrecedes(thisoldest, oldestMXact))
2520  oldestMXact = thisoldest;
2521  }
2522 
2523  LWLockRelease(MultiXactGenLock);
2524 
2525  return oldestMXact;
2526 }
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:1714
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
#define FirstMultiXactId
Definition: multixact.h:24
TransactionId MultiXactId
Definition: c.h:403
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3135
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:1714
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int pageno)
Definition: slru.c:585
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:573
#define MultiXactOffsetCtl
Definition: multixact.c:190
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
void multixact_redo ( XLogReaderState record)

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

3213 {
3214  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
3215 
3216  /* Backup blocks are not used in multixact records */
3217  Assert(!XLogRecHasAnyBlockRefs(record));
3218 
3219  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
3220  {
3221  int pageno;
3222  int slotno;
3223 
3224  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3225 
3226  LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE);
3227 
3228  slotno = ZeroMultiXactOffsetPage(pageno, false);
3230  Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]);
3231 
3232  LWLockRelease(MultiXactOffsetControlLock);
3233  }
3234  else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
3235  {
3236  int pageno;
3237  int slotno;
3238 
3239  memcpy(&pageno, XLogRecGetData(record), sizeof(int));
3240 
3241  LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE);
3242 
3243  slotno = ZeroMultiXactMemberPage(pageno, false);
3245  Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]);
3246 
3247  LWLockRelease(MultiXactMemberControlLock);
3248  }
3249  else if (info == XLOG_MULTIXACT_CREATE_ID)
3250  {
3251  xl_multixact_create *xlrec =
3252  (xl_multixact_create *) XLogRecGetData(record);
3253  TransactionId max_xid;
3254  int i;
3255 
3256  /* Store the data back into the SLRU files */
3257  RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
3258  xlrec->members);
3259 
3260  /* Make sure nextMXact/nextOffset are beyond what this record has */
3261  MultiXactAdvanceNextMXact(xlrec->mid + 1,
3262  xlrec->moff + xlrec->nmembers);
3263 
3264  /*
3265  * Make sure nextXid is beyond any XID mentioned in the record. This
3266  * should be unnecessary, since any XID found here ought to have other
3267  * evidence in the XLOG, but let's be safe.
3268  */
3269  max_xid = XLogRecGetXid(record);
3270  for (i = 0; i < xlrec->nmembers; i++)
3271  {
3272  if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
3273  max_xid = xlrec->members[i].xid;
3274  }
3275 
3276  /*
3277  * We don't expect anyone else to modify nextXid, hence startup
3278  * process doesn't need to hold a lock while checking this. We still
3279  * acquire the lock to modify it, though.
3280  */
3281  if (TransactionIdFollowsOrEquals(max_xid,
3283  {
3284  LWLockAcquire(XidGenLock, LW_EXCLUSIVE);
3285  ShmemVariableCache->nextXid = max_xid;
3287  LWLockRelease(XidGenLock);
3288  }
3289  }
3290  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
3291  {
3292  xl_multixact_truncate xlrec;
3293  int pageno;
3294 
3295  memcpy(&xlrec, XLogRecGetData(record),
3297 
3298  elog(DEBUG1, "replaying multixact truncation: "
3299  "offsets [%u, %u), offsets segments [%x, %x), "
3300  "members [%u, %u), members segments [%x, %x)",
3301  xlrec.startTruncOff, xlrec.endTruncOff,
3304  xlrec.startTruncMemb, xlrec.endTruncMemb,
3307 
3308  /* should not be required, but more than cheap enough */
3309  LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
3310 
3311  /*
3312  * Advance the horizon values, so they're current at the end of
3313  * recovery.
3314  */
3316 
3318 
3319  /*
3320  * During XLOG replay, latest_page_number isn't necessarily set up
3321  * yet; insert a suitable value to bypass the sanity test in
3322  * SimpleLruTruncate.
3323  */
3324  pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
3325  MultiXactOffsetCtl->shared->latest_page_number = pageno;
3327 
3328  LWLockRelease(MultiXactTruncationLock);
3329  }
3330  else
3331  elog(PANIC, "multixact_redo: unknown op code %u", info);
3332 }
#define TransactionIdAdvance(dest)
Definition: transam.h:48
#define DEBUG1
Definition: elog.h:25
uint32 TransactionId
Definition: c.h:393
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:263
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:72
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2343
#define PANIC
Definition: elog.h:53
#define SizeOfMultiXactTruncate
Definition: multixact.h:99
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
Definition: multixact.c:2191
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.h:81
#define XLogRecGetData(decoder)
Definition: xlogreader.h:202
#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:2875
VariableCache ShmemVariableCache
Definition: varsup.c:34
void SimpleLruWritePage(SlruCtl ctl, int slotno)
Definition: slru.c:573
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:198
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:200
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:71
MultiXactOffset startTruncMemb
Definition: multixact.h:95
MultiXactId mid
Definition: multixact.h:78
#define Assert(condition)
Definition: c.h:670
#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:1110
static int ZeroMultiXactMemberPage(int pageno, bool writeXlog)
Definition: multixact.c:1919
int i
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:204
#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:2903
#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:813
int BackendId
Definition: backendid.h:21
#define InvalidMultiXactId
Definition: multixact.h:23
TransactionId MultiXactId
Definition: c.h:403
#define Assert(condition)
Definition: c.h:670
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:813
int BackendId
Definition: backendid.h:21
TransactionId MultiXactId
Definition: c.h:403
#define Assert(condition)
Definition: c.h:670
void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

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

2345 {
2346  LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2348  {
2349  debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2350  MultiXactState->nextMXact = minMulti;
2351  }
2352  if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset))
2353  {
2354  debug_elog3(DEBUG2, "MultiXact: setting next offset to %u",
2355  minMultiOffset);
2356  MultiXactState->nextOffset = minMultiOffset;
2357  }
2358  LWLockRelease(MultiXactGenLock);
2359 }
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:1714
#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:1110
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3135
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3161
void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2368 of file multixact.c.

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

Referenced by xlog_redo().

2369 {
2370  Assert(InRecovery);
2371 
2373  SetMultiXactIdLimit(oldestMulti, oldestMultiDB);
2374 }
bool InRecovery
Definition: xlog.c:190
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
Definition: multixact.c:2191
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
MultiXactId oldestMultiXactId
Definition: multixact.c:216
#define Assert(condition)
Definition: c.h:670
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3135
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:1714
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:1110
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:72
#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:672
#define debug_elog3(a, b, c)
Definition: multixact.c:334
TransactionId MultiXactId
Definition: c.h:403
#define Assert(condition)
Definition: c.h:670
#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:405
#define END_CRIT_SECTION()
Definition: miscadmin.h:132
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:403
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:222
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:72
#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:995
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:992
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:672
#define debug_elog3(a, b, c)
Definition: multixact.c:334
TransactionId MultiXactId
Definition: c.h:403
#define Assert(condition)
Definition: c.h:670
void * palloc(Size size)
Definition: mcxt.c:891
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:222
#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:772
bool TransactionIdIsInProgress(TransactionId xid)
Definition: procarray.c:995
void pfree(void *pointer)
Definition: mcxt.c:992
#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 3149 of file multixact.c.

Referenced by lazy_vacuum_rel(), and TruncateMultiXact().

3150 {
3151  int32 diff = (int32) (multi1 - multi2);
3152 
3153  return (diff <= 0);
3154 }
signed int int32
Definition: c.h:253
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:72
#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:1714
#define DEBUG2
Definition: elog.h:24
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
#define FirstMultiXactId
Definition: multixact.h:24
TransactionId MultiXactId
Definition: c.h:403
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
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:72
#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:1714
#define DEBUG2
Definition: elog.h:24
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
#define FirstMultiXactId
Definition: multixact.h:24
TransactionId MultiXactId
Definition: c.h:403
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3135
int i
#define MaxOldestSlot
Definition: multixact.c:288
int MultiXactMemberFreezeThreshold ( void  )

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

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

Definition at line 3117 of file multixact.c.

References MULTIXACT_MEMBERS_PER_PAGE, and MultiXactOffsetPrecedes().

Referenced by MultiXactShmemInit().

3118 {
3119  MultiXactOffset offset1;
3120  MultiXactOffset offset2;
3121 
3122  offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE;
3123  offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE;
3124 
3125  return MultiXactOffsetPrecedes(offset1, offset2);
3126 }
uint32 MultiXactOffset
Definition: c.h:405
#define MULTIXACT_MEMBERS_PER_PAGE
Definition: multixact.c:142
static bool MultiXactOffsetPrecedes(MultiXactOffset offset1, MultiXactOffset offset2)
Definition: multixact.c:3161
static bool MultiXactOffsetPagePrecedes ( int  page1,
int  page2 
)
static

Definition at line 3099 of file multixact.c.

References FirstMultiXactId, MULTIXACT_OFFSETS_PER_PAGE, and MultiXactIdPrecedes().

Referenced by MultiXactShmemInit().

3100 {
3101  MultiXactId multi1;
3102  MultiXactId multi2;
3103 
3104  multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE;
3105  multi1 += FirstMultiXactId;
3106  multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE;
3107  multi2 += FirstMultiXactId;
3108 
3109  return MultiXactIdPrecedes(multi1, multi2);
3110 }
#define FirstMultiXactId
Definition: multixact.h:24
#define MULTIXACT_OFFSETS_PER_PAGE
Definition: multixact.c:109
TransactionId MultiXactId
Definition: c.h:403
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3135
static bool MultiXactOffsetPrecedes ( MultiXactOffset  offset1,
MultiXactOffset  offset2 
)
static

Definition at line 3161 of file multixact.c.

Referenced by MultiXactAdvanceNextMXact(), and MultiXactMemberPagePrecedes().

3162 {
3163  int32 diff = (int32) (offset1 - offset2);
3164 
3165  return (diff < 0);
3166 }
signed int int32
Definition: c.h:253
static bool MultiXactOffsetWouldWrap ( MultiXactOffset  boundary,
MultiXactOffset  start,
uint32  distance 
)
static

Definition at line 2666 of file multixact.c.

Referenced by GetNewMultiXactId().

2668 {
2669  MultiXactOffset finish;
2670 
2671  /*
2672  * Note that offset number 0 is not used (see GetMultiXactIdMembers), so
2673  * if the addition wraps around the UINT_MAX boundary, skip that value.
2674  */
2675  finish = start + distance;
2676  if (finish < start)
2677  finish++;
2678 
2679  /*-----------------------------------------------------------------------
2680  * When the boundary is numerically greater than the starting point, any
2681  * value numerically between the two is not wrapped:
2682  *
2683  * <----S----B---->
2684  * [---) = F wrapped past B (and UINT_MAX)
2685  * [---) = F not wrapped
2686  * [----] = F wrapped past B
2687  *
2688  * When the boundary is numerically less than the starting point (i.e. the
2689  * UINT_MAX wraparound occurs somewhere in between) then all values in
2690  * between are wrapped:
2691  *
2692  * <----B----S---->
2693  * [---) = F not wrapped past B (but wrapped past UINT_MAX)
2694  * [---) = F wrapped past B (and UINT_MAX)
2695  * [----] = F not wrapped
2696  *-----------------------------------------------------------------------
2697  */
2698  if (start < boundary)
2699  return finish >= boundary || finish < start;
2700  else
2701  return finish >= boundary && finish < start;
2702 }
uint32 MultiXactOffset
Definition: c.h:405
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:101
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
#define DEBUG2
Definition: elog.h:24
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
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:3099
#define MemSet(start, val, len)
Definition: c.h:852
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:100
#define debug_elog2(a, b)
Definition: multixact.c:333
static bool MultiXactMemberPagePrecedes(int page1, int page2)
Definition: multixact.c:3117
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:670
#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:164
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:144
#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:352
#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:352
static void dlist_move_head(dlist_head *head, dlist_node *node)
Definition: ilist.h:385
void * palloc(Size size)
Definition: mcxt.c:891
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:155
dlist_node node
Definition: multixact.c:317
#define dlist_container(type, membername, ptr)
Definition: ilist.h:477
void pfree(void *pointer)
Definition: mcxt.c:992
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:440
#define debug_elog3(a, b, c)
Definition: multixact.c:334
#define NULL
Definition: c.h:226
static dlist_head MXactCache
Definition: multixact.c:322
struct MultiXactMember MultiXactMember
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition: mcxt.c:749
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:550
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:992
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
static char * buf
Definition: pg_test_fsync.c:65
MemoryContext TopMemoryContext
Definition: mcxt.c:43
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:201
void initStringInfo(StringInfo str)
Definition: stringinfo.c:65
#define NULL
Definition: c.h:226
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1152
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:222
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:222
static void PerformMembersTruncation ( MultiXactOffset  oldestOffset,
MultiXactOffset  newOldestOffset 
)
static

Definition at line 2875 of file multixact.c.

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

Referenced by multixact_redo(), and TruncateMultiXact().

2876 {
2877  const int maxsegment = MXOffsetToMemberSegment(MaxMultiXactOffset);
2878  int startsegment = MXOffsetToMemberSegment(oldestOffset);
2879  int endsegment = MXOffsetToMemberSegment(newOldestOffset);
2880  int segment = startsegment;
2881 
2882  /*
2883  * Delete all the segments but the last one. The last segment can still
2884  * contain, possibly partially, valid data.
2885  */
2886  while (segment != endsegment)
2887  {
2888  elog(DEBUG2, "truncating multixact members segment %x", segment);
2890 
2891  /* move to next segment, handling wraparound correctly */
2892  if (segment == maxsegment)
2893  segment = 0;
2894  else
2895  segment += 1;
2896  }
2897 }
#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:1246
#define elog
Definition: elog.h:219
#define MultiXactMemberCtl
Definition: multixact.c:191
static void PerformOffsetsTruncation ( MultiXactId  oldestMulti,
MultiXactId  newOldestMulti 
)
static

Definition at line 2903 of file multixact.c.

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

Referenced by multixact_redo(), and TruncateMultiXact().

2904 {
2905  /*
2906  * We step back one multixact to avoid passing a cutoff page that hasn't
2907  * been created yet in the rare case that oldestMulti would be the first
2908  * item on a page and oldestMulti == nextMulti. In that case, if we
2909  * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
2910  * detection.
2911  */
2913  MultiXactIdToOffsetPage(PreviousMultiXactId(newOldestMulti)));
2914 }
void SimpleLruTruncate(SlruCtl ctl, int cutoffPage)
Definition: slru.c:1153
#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 3335 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.

3336 {
3337  typedef struct
3338  {
3339  MultiXactMember *members;
3340  int nmembers;
3341  int iter;
3342  } mxact;
3343  MultiXactId mxid = PG_GETARG_UINT32(0);
3344  mxact *multi;
3345  FuncCallContext *funccxt;
3346 
3347  if (mxid < FirstMultiXactId)
3348  ereport(ERROR,
3349  (errcode(ERRCODE_INVALID_PARAMETER_VALUE),
3350  errmsg("invalid MultiXactId: %u", mxid)));
3351 
3352  if (SRF_IS_FIRSTCALL())
3353  {
3354  MemoryContext oldcxt;
3355  TupleDesc tupdesc;
3356 
3357  funccxt = SRF_FIRSTCALL_INIT();
3358  oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx);
3359 
3360  multi = palloc(sizeof(mxact));
3361  /* no need to allow for old values here */
3362  multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false,
3363  false);
3364  multi->iter = 0;
3365 
3366  tupdesc = CreateTemplateTupleDesc(2, false);
3367  TupleDescInitEntry(tupdesc, (AttrNumber) 1, "xid",
3368  XIDOID, -1, 0);
3369  TupleDescInitEntry(tupdesc, (AttrNumber) 2, "mode",
3370  TEXTOID, -1, 0);
3371 
3372  funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc);
3373  funccxt->user_fctx = multi;
3374 
3375  MemoryContextSwitchTo(oldcxt);
3376  }
3377 
3378  funccxt = SRF_PERCALL_SETUP();
3379  multi = (mxact *) funccxt->user_fctx;
3380 
3381  while (multi->iter < multi->nmembers)
3382  {
3383  HeapTuple tuple;
3384  char *values[2];
3385 
3386  values[0] = psprintf("%u", multi->members[multi->iter].xid);
3387  values[1] = mxstatus_to_string(multi->members[multi->iter].status);
3388 
3389  tuple = BuildTupleFromCStrings(funccxt->attinmeta, values);
3390 
3391  multi->iter++;
3392  pfree(values[0]);
3393  SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple));
3394  }
3395 
3396  if (multi->nmembers > 0)
3397  pfree(multi->members);
3398  pfree(multi);
3399 
3400  SRF_RETURN_DONE(funccxt);
3401 }
#define PG_GETARG_UINT32(n)
Definition: fmgr.h:226
#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:992
#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:493
#define ereport(elevel, rest)
Definition: elog.h:122
AttInMetadata * TupleDescGetAttInMetadata(TupleDesc tupdesc)
Definition: execTuples.c:1068
TransactionId MultiXactId
Definition: c.h:403
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:162
void * user_fctx
Definition: funcapi.h:90
void * palloc(Size size)
Definition: mcxt.c:891
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:72
static MultiXactId * OldestMemberMXactId
Definition: multixact.c:292
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
static int MXactCacheMembers
Definition: multixact.c:323
BackendId TwoPhaseGetDummyBackendId(TransactionId xid)
Definition: twophase.c:813
#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:403
#define NULL
Definition: c.h:226
static dlist_head MXactCache
Definition: multixact.c:322
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
static MemoryContext MXactContext
Definition: multixact.c:324
static bool ReadMultiXactCounts ( uint32 multixacts,
MultiXactOffset members 
)
static

Definition at line 2756 of file multixact.c.

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

Referenced by MultiXactMemberFreezeThreshold().

2757 {
2758  MultiXactOffset nextOffset;
2759  MultiXactOffset oldestOffset;
2760  MultiXactId oldestMultiXactId;
2761  MultiXactId nextMultiXactId;
2762  bool oldestOffsetKnown;
2763 
2764  LWLockAcquire(MultiXactGenLock, LW_SHARED);
2765  nextOffset = MultiXactState->nextOffset;
2766  oldestMultiXactId = MultiXactState->oldestMultiXactId;
2767  nextMultiXactId = MultiXactState->nextMXact;
2768  oldestOffset = MultiXactState->oldestOffset;
2769  oldestOffsetKnown = MultiXactState->oldestOffsetKnown;
2770  LWLockRelease(MultiXactGenLock);
2771 
2772  if (!oldestOffsetKnown)
2773  return false;
2774 
2775  *members = nextOffset - oldestOffset;
2776  *multixacts = nextMultiXactId - oldestMultiXactId;
2777  return true;
2778 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:405
MultiXactOffset nextOffset
Definition: multixact.c:206
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1714
MultiXactId oldestMultiXactId
Definition: multixact.c:216
MultiXactOffset oldestOffset
Definition: multixact.c:224
TransactionId MultiXactId
Definition: c.h:403
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
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:1714
#define FirstMultiXactId
Definition: multixact.h:24
TransactionId MultiXactId
Definition: c.h:403
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
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:405
uint32 TransactionId
Definition: c.h:393
#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:1714
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:370
MultiXactStatus status
Definition: multixact.h:62
unsigned int uint32
Definition: c.h:265
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define Assert(condition)
Definition: c.h:670
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
#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:222
#define MultiXactMemberCtl
Definition: multixact.c:191
void SetMultiXactIdLimit ( MultiXactId  oldest_datminmxid,
Oid  oldest_datoid 
)

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

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

Definition at line 2540 of file multixact.c.

References Assert, DEBUG1, ereport, errmsg(), find_multixact_start(), MultiXactStateData::finishedStartup, IsUnderPostmaster, 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().

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

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

Referenced by TruncateMultiXact().

2853 {
2854  mxtruncinfo *trunc = (mxtruncinfo *) data;
2855 
2856  if (trunc->earliestExistingPage == -1 ||
2857  ctl->PagePrecedes(segpage, trunc->earliestExistingPage))
2858  {
2859  trunc->earliestExistingPage = segpage;
2860  }
2861 
2862  return false; /* keep going */
2863 }
bool(* PagePrecedes)(int, int)
Definition: slru.h:132
int earliestExistingPage
Definition: multixact.c:2844
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:405
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:403
#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);
2099 }
MultiXactId nextMXact
Definition: multixact.c:203
uint32 MultiXactOffset
Definition: c.h:405
uint32 TransactionId
Definition: c.h:393
MultiXactOffset nextOffset
Definition: multixact.c:206
#define MemSet(start, val, len)
Definition: c.h:852
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
unsigned int Oid
Definition: postgres_ext.h:31
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:163
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
Definition: multixact.c:2191
#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:1714
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:370
#define MultiXactOffsetCtl
Definition: multixact.c:190
TransactionId MultiXactId
Definition: c.h:403
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1110
#define MultiXactMemberCtl
Definition: multixact.c:191
void TruncateMultiXact ( MultiXactId  newOldestMulti,
Oid  newOldestMultiDB 
)

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

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

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

3190 {
3191  XLogRecPtr recptr;
3192  xl_multixact_truncate xlrec;
3193 
3194  xlrec.oldestMultiDB = oldestMultiDB;
3195 
3196  xlrec.startTruncOff = startTruncOff;
3197  xlrec.endTruncOff = endTruncOff;
3198 
3199  xlrec.startTruncMemb = startTruncMemb;
3200  xlrec.endTruncMemb = endTruncMemb;
3201 
3202  XLogBeginInsert();
3203  XLogRegisterData((char *) (&xlrec), SizeOfMultiXactTruncate);
3204  recptr = XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_TRUNCATE_ID);
3205  XLogFlush(recptr);
3206 }
void XLogFlush(XLogRecPtr record)
Definition: xlog.c:2744
#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 3173 of file multixact.c.

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

Referenced by ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

3174 {
3175  XLogBeginInsert();
3176  XLogRegisterData((char *) (&pageno), sizeof(int));
3177  (void) XLogInsert(RM_MULTIXACT_ID, info);
3178 }
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:3173
#define MultiXactMemberCtl
Definition: multixact.c:191
int SimpleLruZeroPage(SlruCtl ctl, int pageno)
Definition: slru.c:258
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:3173
#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:258

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.