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, bool is_startup)
 
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:229
static dlist_head MXactCache
Definition: multixact.c:322
static MemoryContext MXactContext
Definition: multixact.c:324
void AtPrepare_MultiXact ( void  )

Definition at line 1691 of file multixact.c.

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

Referenced by PrepareTransaction().

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

Definition at line 1866 of file multixact.c.

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

Referenced by BootStrapXLOG().

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

Definition at line 2140 of file multixact.c.

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruFlush().

Referenced by CheckPointGuts().

2141 {
2142  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
2143 
2144  /* Flush dirty MultiXact pages to disk */
2147 
2148  TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
2149 }
void SimpleLruFlush(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1100
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define MultiXactMemberCtl
Definition: multixact.c:191
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:409
uint32 TransactionId
Definition: c.h:397
MultiXactOffset nextOffset
Definition: multixact.c:206
int errcode(int sqlerrcode)
Definition: elog.c:575
#define MXOffsetToMemberPage(xid)
Definition: multixact.c:159
static MultiXactId * OldestVisibleMXactId
Definition: multixact.c:293
#define MXOffsetToFlagsOffset(xid)
Definition: multixact.c:163
#define MultiXactIdToOffsetEntry(xid)
Definition: multixact.c:113
#define MultiXactIdToOffsetPage(xid)
Definition: multixact.c:111
static MultiXactStateData * MultiXactState
Definition: multixact.c:291
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1715
MultiXactId oldestMultiXactId
Definition: multixact.c:216
void pg_usleep(long microsec)
Definition: signal.c:53
#define ERROR
Definition: elog.h:43
TransactionId xid
Definition: multixact.h:61
#define MXOffsetToMemberOffset(xid)
Definition: multixact.c:172
#define MXACT_MEMBER_XACT_BITMASK
Definition: multixact.c:132
int SimpleLruReadPage(SlruCtl ctl, int pageno, bool write_ok, TransactionId xid)
Definition: slru.c:371
#define DEBUG2
Definition: elog.h:24
MultiXactStatus status
Definition: multixact.h:62
unsigned int uint32
Definition: c.h:268
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
#define debug_elog2(a, b)
Definition: multixact.c:333
#define FirstMultiXactId
Definition: multixact.h:24
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1631
#define ereport(elevel, rest)
Definition: elog.h:122
#define MultiXactOffsetCtl
Definition: multixact.c:190
#define debug_elog3(a, b, c)
Definition: multixact.c:334
TransactionId MultiXactId
Definition: c.h:407
#define NULL
Definition: c.h:229
#define Assert(condition)
Definition: c.h:675
static void MultiXactIdSetOldestVisible(void)
Definition: multixact.c:680
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
static void mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1561
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:3140
void * palloc(Size size)
Definition: mcxt.c:849
int errmsg(const char *fmt,...)
Definition: elog.c:797
static int mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
Definition: multixact.c:1515
int i
#define CHECK_FOR_INTERRUPTS()
Definition: miscadmin.h:97
#define TransactionIdIsValid(xid)
Definition: transam.h:41
#define MultiXactMemberCtl
Definition: multixact.c:191
MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2491 of file multixact.c.

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

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

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

References Assert, DEBUG1, elog, xl_multixact_truncate::endTruncMemb, xl_multixact_truncate::endTruncOff, i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), xl_multixact_create::members, xl_multixact_create::mid, xl_multixact_create::moff, MultiXactAdvanceNextMXact(), MultiXactIdToOffsetPage, MultiXactIdToOffsetSegment, MultiXactMemberCtl, MultiXactOffsetCtl, MXOffsetToMemberSegment, VariableCacheData::nextXid, xl_multixact_create::nmembers, xl_multixact_truncate::oldestMultiDB, PANIC, PerformMembersTruncation(), PerformOffsetsTruncation(), RecordNewMultiXact(), SetMultiXactIdLimit(), ShmemVariableCache, SimpleLruWritePage(), SizeOfMultiXactTruncate, xl_multixact_truncate::startTruncMemb, xl_multixact_truncate::startTruncOff, TransactionIdAdvance, TransactionIdFollowsOrEquals(), TransactionIdPrecedes(), MultiXactMember::xid, XLOG_MULTIXACT_CREATE_ID, XLOG_MULTIXACT_TRUNCATE_ID, XLOG_MULTIXACT_ZERO_MEM_PAGE, XLOG_MULTIXACT_ZERO_OFF_PAGE, XLogRecGetData, XLogRecGetInfo, XLogRecGetXid, XLogRecHasAnyBlockRefs, XLR_INFO_MASK, ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().

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

Definition at line 1791 of file multixact.c.

References multixact_twophase_postcommit().

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

Definition at line 1776 of file multixact.c.

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

Referenced by multixact_twophase_postabort().

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

Definition at line 1755 of file multixact.c.

References Assert, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().

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

Definition at line 2347 of file multixact.c.

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

Referenced by multixact_redo(), and xlog_redo().

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

Definition at line 2372 of file multixact.c.

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

Referenced by xlog_redo().

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

Definition at line 2118 of file multixact.c.

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

Referenced by CreateCheckPoint().

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

Definition at line 384 of file multixact.c.

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

Referenced by compute_new_xmax_infomask().

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

Definition at line 746 of file multixact.c.

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

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

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

Definition at line 437 of file multixact.c.

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

Referenced by compute_new_xmax_infomask().

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

Definition at line 549 of file multixact.c.

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

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

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

Definition at line 3154 of file multixact.c.

Referenced by lazy_vacuum_rel(), and TruncateMultiXact().

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

Definition at line 623 of file multixact.c.

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

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

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

Definition at line 2817 of file multixact.c.

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

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

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

Definition at line 1820 of file multixact.c.

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

Referenced by CreateSharedMemoryAndSemaphores().

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

Definition at line 1803 of file multixact.c.

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

Referenced by CreateSharedMemoryAndSemaphores().

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

Definition at line 1631 of file multixact.c.

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

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

1632 {
1633  static char *str = NULL;
1635  int i;
1636 
1637  if (str != NULL)
1638  pfree(str);
1639 
1640  initStringInfo(&buf);
1641 
1642  appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1643  mxstatus_to_string(members[0].status));
1644 
1645  for (i = 1; i < nmembers; i++)
1646  appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1647  mxstatus_to_string(members[i].status));
1648 
1649  appendStringInfoChar(&buf, ']');
1651  pfree(buf.data);
1652  return str;
1653 }
void pfree(void *pointer)
Definition: mcxt.c:950
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition: stringinfo.c:78
static char * buf
Definition: pg_test_fsync.c:66
MemoryContext TopMemoryContext
Definition: mcxt.c:43
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:169
void initStringInfo(StringInfo str)
Definition: stringinfo.c:46
#define NULL
Definition: c.h:229
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1064
int i
static char * mxstatus_to_string(MultiXactStatus status)
Definition: multixact.c:1608
static void static void status(const char *fmt,...) pg_attribute_printf(1
Definition: pg_regress.c:224
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:1715
static int MXactCacheMembers
Definition: multixact.c:323
BackendId TwoPhaseGetDummyBackendId(TransactionId xid)
Definition: twophase.c:856
#define MultiXactIdIsValid(multi)
Definition: multixact.h:27
int BackendId
Definition: backendid.h:21
#define InvalidMultiXactId
Definition: multixact.h:23
static void dlist_init(dlist_head *head)
Definition: ilist.h:278
TransactionId MultiXactId
Definition: c.h:407
#define NULL
Definition: c.h:229
static dlist_head MXactCache
Definition: multixact.c:322
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1111
static MemoryContext MXactContext
Definition: multixact.c:324
MultiXactId ReadNextMultiXactId ( void  )

Definition at line 721 of file multixact.c.

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

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

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

Definition at line 2194 of file multixact.c.

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

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

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

Definition at line 2105 of file multixact.c.

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruFlush().

Referenced by ShutdownXLOG().

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

Definition at line 1980 of file multixact.c.

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

Referenced by StartupXLOG().

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

Definition at line 2003 of file multixact.c.

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

Referenced by StartupXLOG().

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

Definition at line 2933 of file multixact.c.

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

Referenced by vac_truncate_clog().

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