PostgreSQL Source Code  git master
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros
multixact.h File Reference
#include "access/xlogreader.h"
#include "lib/stringinfo.h"
Include dependency graph for multixact.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  MultiXactMember
 
struct  xl_multixact_create
 
struct  xl_multixact_truncate
 

Macros

#define InvalidMultiXactId   ((MultiXactId) 0)
 
#define FirstMultiXactId   ((MultiXactId) 1)
 
#define MaxMultiXactId   ((MultiXactId) 0xFFFFFFFF)
 
#define MultiXactIdIsValid(multi)   ((multi) != InvalidMultiXactId)
 
#define MaxMultiXactOffset   ((MultiXactOffset) 0xFFFFFFFF)
 
#define NUM_MXACTOFFSET_BUFFERS   8
 
#define NUM_MXACTMEMBER_BUFFERS   16
 
#define MaxMultiXactStatus   MultiXactStatusUpdate
 
#define ISUPDATE_from_mxstatus(status)   ((status) > MultiXactStatusForUpdate)
 
#define XLOG_MULTIXACT_ZERO_OFF_PAGE   0x00
 
#define XLOG_MULTIXACT_ZERO_MEM_PAGE   0x10
 
#define XLOG_MULTIXACT_CREATE_ID   0x20
 
#define XLOG_MULTIXACT_TRUNCATE_ID   0x30
 
#define SizeOfMultiXactCreate   (offsetof(xl_multixact_create, members))
 
#define SizeOfMultiXactTruncate   (sizeof(xl_multixact_truncate))
 

Typedefs

typedef struct MultiXactMember MultiXactMember
 
typedef struct xl_multixact_create xl_multixact_create
 
typedef struct
xl_multixact_truncate 
xl_multixact_truncate
 

Enumerations

enum  MultiXactStatus {
  MultiXactStatusForKeyShare = 0x00, MultiXactStatusForShare = 0x01, MultiXactStatusForNoKeyUpdate = 0x02, MultiXactStatusForUpdate = 0x03,
  MultiXactStatusNoKeyUpdate = 0x04, MultiXactStatusUpdate = 0x05
}
 

Functions

MultiXactId MultiXactIdCreate (TransactionId xid1, MultiXactStatus status1, TransactionId xid2, MultiXactStatus status2)
 
MultiXactId MultiXactIdExpand (MultiXactId multi, TransactionId xid, MultiXactStatus status)
 
MultiXactId MultiXactIdCreateFromMembers (int nmembers, MultiXactMember *members)
 
MultiXactId ReadNextMultiXactId (void)
 
bool MultiXactIdIsRunning (MultiXactId multi, bool isLockOnly)
 
void MultiXactIdSetOldestMember (void)
 
int GetMultiXactIdMembers (MultiXactId multi, MultiXactMember **xids, bool allow_old, bool isLockOnly)
 
bool MultiXactIdPrecedes (MultiXactId multi1, MultiXactId multi2)
 
bool MultiXactIdPrecedesOrEquals (MultiXactId multi1, MultiXactId multi2)
 
void AtEOXact_MultiXact (void)
 
void AtPrepare_MultiXact (void)
 
void PostPrepare_MultiXact (TransactionId xid)
 
Size MultiXactShmemSize (void)
 
void MultiXactShmemInit (void)
 
void BootStrapMultiXact (void)
 
void StartupMultiXact (void)
 
void TrimMultiXact (void)
 
void ShutdownMultiXact (void)
 
void SetMultiXactIdLimit (MultiXactId oldest_datminmxid, Oid oldest_datoid)
 
void MultiXactGetCheckptMulti (bool is_shutdown, MultiXactId *nextMulti, MultiXactOffset *nextMultiOffset, MultiXactId *oldestMulti, Oid *oldestMultiDB)
 
void CheckPointMultiXact (void)
 
MultiXactId GetOldestMultiXactId (void)
 
void TruncateMultiXact (MultiXactId oldestMulti, Oid oldestMultiDB)
 
void MultiXactSetNextMXact (MultiXactId nextMulti, MultiXactOffset nextMultiOffset)
 
void MultiXactAdvanceNextMXact (MultiXactId minMulti, MultiXactOffset minMultiOffset)
 
void MultiXactAdvanceOldest (MultiXactId oldestMulti, Oid oldestMultiDB)
 
int MultiXactMemberFreezeThreshold (void)
 
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)
 
void multixact_redo (XLogReaderState *record)
 
void multixact_desc (StringInfo buf, XLogReaderState *record)
 
const char * multixact_identify (uint8 info)
 
char * mxid_to_string (MultiXactId multi, int nmembers, MultiXactMember *members)
 

Macro Definition Documentation

#define MaxMultiXactId   ((MultiXactId) 0xFFFFFFFF)

Definition at line 25 of file multixact.h.

Referenced by SetMultiXactIdLimit().

#define MaxMultiXactOffset   ((MultiXactOffset) 0xFFFFFFFF)

Definition at line 29 of file multixact.h.

Referenced by ExtendMultiXactMember(), and PerformMembersTruncation().

#define MaxMultiXactStatus   MultiXactStatusUpdate

Definition at line 52 of file multixact.h.

#define NUM_MXACTMEMBER_BUFFERS   16

Definition at line 33 of file multixact.h.

Referenced by MultiXactShmemInit(), and MultiXactShmemSize().

#define NUM_MXACTOFFSET_BUFFERS   8

Definition at line 32 of file multixact.h.

Referenced by MultiXactShmemInit(), and MultiXactShmemSize().

#define SizeOfMultiXactCreate   (offsetof(xl_multixact_create, members))

Definition at line 84 of file multixact.h.

Referenced by MultiXactIdCreateFromMembers().

#define SizeOfMultiXactTruncate   (sizeof(xl_multixact_truncate))

Definition at line 99 of file multixact.h.

Referenced by multixact_redo(), and WriteMTruncateXlogRec().

#define XLOG_MULTIXACT_CREATE_ID   0x20
#define XLOG_MULTIXACT_TRUNCATE_ID   0x30
#define XLOG_MULTIXACT_ZERO_MEM_PAGE   0x10
#define XLOG_MULTIXACT_ZERO_OFF_PAGE   0x00

Typedef Documentation

Enumeration Type Documentation

Enumerator
MultiXactStatusForKeyShare 
MultiXactStatusForShare 
MultiXactStatusForNoKeyUpdate 
MultiXactStatusForUpdate 
MultiXactStatusNoKeyUpdate 
MultiXactStatusUpdate 

Definition at line 40 of file multixact.h.

41 {
46  /* an update that doesn't touch "key" columns */
48  /* other updates, and delete */
MultiXactStatus
Definition: multixact.h:40

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
int GetMultiXactIdMembers ( MultiXactId  multi,
MultiXactMember **  xids,
bool  allow_old,
bool  isLockOnly 
)

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
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
void multixact_desc ( StringInfo  buf,
XLogReaderState record 
)

Definition at line 50 of file mxactdesc.c.

References appendStringInfo(), xl_multixact_truncate::endTruncMemb, xl_multixact_truncate::endTruncOff, i, xl_multixact_create::members, xl_multixact_create::mid, xl_multixact_create::moff, xl_multixact_create::nmembers, out_member(), xl_multixact_truncate::startTruncMemb, xl_multixact_truncate::startTruncOff, XLOG_MULTIXACT_CREATE_ID, XLOG_MULTIXACT_TRUNCATE_ID, XLOG_MULTIXACT_ZERO_MEM_PAGE, XLOG_MULTIXACT_ZERO_OFF_PAGE, XLogRecGetData, XLogRecGetInfo, and XLR_INFO_MASK.

51 {
52  char *rec = XLogRecGetData(record);
53  uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
54 
55  if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE ||
57  {
58  int pageno;
59 
60  memcpy(&pageno, rec, sizeof(int));
61  appendStringInfo(buf, "%d", pageno);
62  }
63  else if (info == XLOG_MULTIXACT_CREATE_ID)
64  {
66  int i;
67 
68  appendStringInfo(buf, "%u offset %u nmembers %d: ", xlrec->mid,
69  xlrec->moff, xlrec->nmembers);
70  for (i = 0; i < xlrec->nmembers; i++)
71  out_member(buf, &xlrec->members[i]);
72  }
73  else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
74  {
76 
77  appendStringInfo(buf, "offsets [%u, %u), members [%u, %u)",
78  xlrec->startTruncOff, xlrec->endTruncOff,
79  xlrec->startTruncMemb, xlrec->endTruncMemb);
80  }
81 }
unsigned char uint8
Definition: c.h:263
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:72
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition: multixact.h:81
#define XLogRecGetData(decoder)
Definition: xlogreader.h:202
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:110
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:73
MultiXactOffset moff
Definition: multixact.h:79
static void out_member(StringInfo buf, MultiXactMember *member)
Definition: mxactdesc.c:20
#define XLogRecGetInfo(decoder)
Definition: xlogreader.h:198
MultiXactOffset endTruncMemb
Definition: multixact.h:96
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:71
MultiXactOffset startTruncMemb
Definition: multixact.h:95
MultiXactId mid
Definition: multixact.h:78
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:74
MultiXactId startTruncOff
Definition: multixact.h:91
int i
MultiXactId endTruncOff
Definition: multixact.h:92
const char* multixact_identify ( uint8  info)

Definition at line 84 of file mxactdesc.c.

References NULL, XLOG_MULTIXACT_CREATE_ID, XLOG_MULTIXACT_TRUNCATE_ID, XLOG_MULTIXACT_ZERO_MEM_PAGE, XLOG_MULTIXACT_ZERO_OFF_PAGE, and XLR_INFO_MASK.

85 {
86  const char *id = NULL;
87 
88  switch (info & ~XLR_INFO_MASK)
89  {
91  id = "ZERO_OFF_PAGE";
92  break;
94  id = "ZERO_MEM_PAGE";
95  break;
97  id = "CREATE_ID";
98  break;
100  id = "TRUNCATE_ID";
101  break;
102  }
103 
104  return id;
105 }
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition: multixact.h:72
#define XLOG_MULTIXACT_CREATE_ID
Definition: multixact.h:73
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition: multixact.h:71
#define NULL
Definition: c.h:226
#define XLR_INFO_MASK
Definition: xlogrecord.h:62
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition: multixact.h:74
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
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
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
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
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
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
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
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
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  oldestMulti,
Oid  oldestMultiDB 
)

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