PostgreSQL Source Code git master
Loading...
Searching...
No Matches
multixact.c File Reference
#include "postgres.h"
#include "access/multixact.h"
#include "access/multixact_internal.h"
#include "access/slru.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "access/xlog.h"
#include "access/xloginsert.h"
#include "access/xlogutils.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "pgstat.h"
#include "postmaster/autovacuum.h"
#include "storage/pmsignal.h"
#include "storage/proc.h"
#include "storage/procarray.h"
#include "storage/subsystems.h"
#include "utils/guc_hooks.h"
#include "utils/injection_point.h"
#include "utils/lsyscache.h"
#include "utils/memutils.h"
Include dependency graph for multixact.c:

Go to the source code of this file.

Data Structures

struct  MultiXactStateData
 
struct  mXactCacheEnt
 
struct  MultiXactMemberSlruReadContext
 

Macros

#define MULTIXACT_MEMBER_LOW_THRESHOLD   UINT64CONST(2000000000)
 
#define MULTIXACT_MEMBER_HIGH_THRESHOLD   UINT64CONST(4000000000)
 
#define MultiXactOffsetCtl   (&MultiXactOffsetSlruDesc)
 
#define MultiXactMemberCtl   (&MultiXactMemberSlruDesc)
 
#define NumMemberSlots   (MaxBackends + max_prepared_xacts)
 
#define NumVisibleSlots   MaxBackends
 
#define MAX_CACHE_ENTRIES   256
 
#define debug_elog2(a, b)
 
#define debug_elog3(a, b, c)
 
#define debug_elog4(a, b, c, d)
 
#define debug_elog5(a, b, c, d, e)
 
#define debug_elog6(a, b, c, d, e, f)
 

Typedefs

typedef struct MultiXactStateData MultiXactStateData
 
typedef struct mXactCacheEnt mXactCacheEnt
 
typedef struct MultiXactMemberSlruReadContext MultiXactMemberSlruReadContext
 

Functions

static MultiXactId NextMultiXactId (MultiXactId multi)
 
static MultiXactId PreviousMultiXactId (MultiXactId multi)
 
static bool MultiXactOffsetPagePrecedes (int64 page1, int64 page2)
 
static int MultiXactOffsetIoErrorDetail (const void *opaque_data)
 
static bool MultiXactMemberPagePrecedes (int64 page1, int64 page2)
 
static int MultiXactMemberIoErrorDetail (const void *opaque_data)
 
static void MultiXactShmemRequest (void *arg)
 
static void MultiXactShmemInit (void *arg)
 
static void MultiXactShmemAttach (void *arg)
 
static MultiXactIdMyOldestMemberMXactIdSlot (void)
 
static MultiXactIdPreparedXactOldestMemberMXactIdSlot (ProcNumber procno)
 
static MultiXactIdMyOldestVisibleMXactIdSlot (void)
 
static void MultiXactIdSetOldestVisible (void)
 
static void RecordNewMultiXact (MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
 
static MultiXactId GetNewMultiXactId (int nmembers, MultiXactOffset *offset)
 
static int mxactMemberComparator (const void *arg1, const void *arg2)
 
static MultiXactId mXactCacheGetBySet (int nmembers, MultiXactMember *members)
 
static int mXactCacheGetById (MultiXactId multi, MultiXactMember **members)
 
static void mXactCachePut (MultiXactId multi, int nmembers, MultiXactMember *members)
 
static void ExtendMultiXactOffset (MultiXactId multi)
 
static void ExtendMultiXactMember (MultiXactOffset offset, int nmembers)
 
static void SetOldestOffset (void)
 
static bool find_multixact_start (MultiXactId multi, MultiXactOffset *result)
 
static void WriteMTruncateXlogRec (Oid oldestMultiDB, MultiXactId endTruncOff, MultiXactOffset endTruncMemb)
 
MultiXactId MultiXactIdCreate (TransactionId xid1, MultiXactStatus status1, TransactionId xid2, MultiXactStatus status2)
 
MultiXactId MultiXactIdExpand (MultiXactId multi, TransactionId xid, MultiXactStatus status)
 
bool MultiXactIdIsRunning (MultiXactId multi, bool isLockOnly)
 
void MultiXactIdSetOldestMember (void)
 
MultiXactId ReadNextMultiXactId (void)
 
void ReadMultiXactIdRange (MultiXactId *oldest, MultiXactId *next)
 
MultiXactId MultiXactIdCreateFromMembers (int nmembers, MultiXactMember *members)
 
int GetMultiXactIdMembers (MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool isLockOnly)
 
charmxstatus_to_string (MultiXactStatus status)
 
charmxid_to_string (MultiXactId multi, int nmembers, MultiXactMember *members)
 
void AtEOXact_MultiXact (void)
 
void AtPrepare_MultiXact (void)
 
void PostPrepare_MultiXact (FullTransactionId fxid)
 
void multixact_twophase_recover (FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postcommit (FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
 
void multixact_twophase_postabort (FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
 
bool check_multixact_offset_buffers (int *newval, void **extra, GucSource source)
 
bool check_multixact_member_buffers (int *newval, void **extra, GucSource source)
 
void BootStrapMultiXact (void)
 
void StartupMultiXact (void)
 
void TrimMultiXact (void)
 
void MultiXactGetCheckptMulti (bool is_shutdown, MultiXactId *nextMulti, MultiXactOffset *nextMultiOffset, MultiXactId *oldestMulti, Oid *oldestMultiDB)
 
void CheckPointMultiXact (void)
 
void MultiXactSetNextMXact (MultiXactId nextMulti, MultiXactOffset nextMultiOffset)
 
void SetMultiXactIdLimit (MultiXactId oldest_datminmxid, Oid oldest_datoid)
 
void MultiXactAdvanceNextMXact (MultiXactId minMulti, MultiXactOffset minMultiOffset)
 
void MultiXactAdvanceOldest (MultiXactId oldestMulti, Oid oldestMultiDB)
 
MultiXactId GetOldestMultiXactId (void)
 
void GetMultiXactInfo (uint32 *multixacts, MultiXactOffset *nextOffset, MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset)
 
int MultiXactMemberFreezeThreshold (void)
 
static void PerformMembersTruncation (MultiXactOffset newOldestOffset)
 
static void PerformOffsetsTruncation (MultiXactId newOldestMulti)
 
void TruncateMultiXact (MultiXactId newOldestMulti, Oid newOldestMultiDB)
 
bool MultiXactIdPrecedes (MultiXactId multi1, MultiXactId multi2)
 
bool MultiXactIdPrecedesOrEquals (MultiXactId multi1, MultiXactId multi2)
 
void multixact_redo (XLogReaderState *record)
 
int multixactoffsetssyncfiletag (const FileTag *ftag, char *path)
 
int multixactmemberssyncfiletag (const FileTag *ftag, char *path)
 

Variables

static SlruDesc MultiXactOffsetSlruDesc
 
static SlruDesc MultiXactMemberSlruDesc
 
static MultiXactStateDataMultiXactState
 
static MultiXactIdOldestMemberMXactId
 
static MultiXactIdOldestVisibleMXactId
 
const ShmemCallbacks MultiXactShmemCallbacks
 
static dclist_head MXactCache = DCLIST_STATIC_INIT(MXactCache)
 
static MemoryContext MXactContext = NULL
 

Macro Definition Documentation

◆ debug_elog2

#define debug_elog2 (   a,
  b 
)

Definition at line 310 of file multixact.c.

◆ debug_elog3

#define debug_elog3 (   a,
  b,
  c 
)

Definition at line 311 of file multixact.c.

◆ debug_elog4

#define debug_elog4 (   a,
  b,
  c,
 
)

Definition at line 312 of file multixact.c.

◆ debug_elog5

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

Definition at line 313 of file multixact.c.

◆ debug_elog6

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

Definition at line 314 of file multixact.c.

◆ MAX_CACHE_ENTRIES

#define MAX_CACHE_ENTRIES   256

Definition at line 299 of file multixact.c.

◆ MULTIXACT_MEMBER_HIGH_THRESHOLD

#define MULTIXACT_MEMBER_HIGH_THRESHOLD   UINT64CONST(4000000000)

Definition at line 100 of file multixact.c.

◆ MULTIXACT_MEMBER_LOW_THRESHOLD

#define MULTIXACT_MEMBER_LOW_THRESHOLD   UINT64CONST(2000000000)

Definition at line 99 of file multixact.c.

◆ MultiXactMemberCtl

#define MultiXactMemberCtl   (&MultiXactMemberSlruDesc)

Definition at line 126 of file multixact.c.

◆ MultiXactOffsetCtl

#define MultiXactOffsetCtl   (&MultiXactOffsetSlruDesc)

Definition at line 125 of file multixact.c.

◆ NumMemberSlots

#define NumMemberSlots   (MaxBackends + max_prepared_xacts)

Definition at line 221 of file multixact.c.

◆ NumVisibleSlots

#define NumVisibleSlots   MaxBackends

Definition at line 222 of file multixact.c.

Typedef Documentation

◆ MultiXactMemberSlruReadContext

◆ MultiXactStateData

◆ mXactCacheEnt

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1628 of file multixact.c.

1629{
1630 /*
1631 * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1632 * which should only be valid while within a transaction.
1633 *
1634 * We assume that storing a MultiXactId is atomic and so we need not take
1635 * MultiXactGenLock to do this.
1636 */
1639
1640 /*
1641 * Discard the local MultiXactId cache. Since MXactContext was created as
1642 * a child of TopTransactionContext, we needn't delete it explicitly.
1643 */
1646}
static void dclist_init(dclist_head *head)
Definition ilist.h:671
static MultiXactId * MyOldestVisibleMXactIdSlot(void)
Definition multixact.c:268
static MemoryContext MXactContext
Definition multixact.c:301
static dclist_head MXactCache
Definition multixact.c:300
static MultiXactId * MyOldestMemberMXactIdSlot(void)
Definition multixact.c:240
#define InvalidMultiXactId
Definition multixact.h:25
static int fb(int x)

References dclist_init(), fb(), InvalidMultiXactId, MXactCache, MXactContext, MyOldestMemberMXactIdSlot(), and MyOldestVisibleMXactIdSlot().

Referenced by AbortTransaction(), CommitTransaction(), and test_read_multixact().

◆ AtPrepare_MultiXact()

void AtPrepare_MultiXact ( void  )

Definition at line 1656 of file multixact.c.

1657{
1659
1662 &myOldestMember, sizeof(MultiXactId));
1663}
TransactionId MultiXactId
Definition c.h:746
#define MultiXactIdIsValid(multi)
Definition multixact.h:29
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition twophase.c:1277
#define TWOPHASE_RM_MULTIXACT_ID

References fb(), MultiXactIdIsValid, MyOldestMemberMXactIdSlot(), RegisterTwoPhaseRecord(), and TWOPHASE_RM_MULTIXACT_ID.

Referenced by PrepareTransaction().

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 1863 of file multixact.c.

1864{
1865 /* Zero the initial pages and flush them to disk */
1868}
#define MultiXactMemberCtl
Definition multixact.c:126
#define MultiXactOffsetCtl
Definition multixact.c:125
void SimpleLruZeroAndWritePage(SlruDesc *ctl, int64 pageno)
Definition slru.c:466

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruZeroAndWritePage().

Referenced by BootStrapXLOG().

◆ check_multixact_member_buffers()

bool check_multixact_member_buffers ( int newval,
void **  extra,
GucSource  source 
)

Definition at line 1852 of file multixact.c.

1853{
1854 return check_slru_buffers("multixact_member_buffers", newval);
1855}
#define newval
bool check_slru_buffers(const char *name, int *newval)
Definition slru.c:377

References check_slru_buffers(), and newval.

◆ check_multixact_offset_buffers()

bool check_multixact_offset_buffers ( int newval,
void **  extra,
GucSource  source 
)

Definition at line 1843 of file multixact.c.

1844{
1845 return check_slru_buffers("multixact_offset_buffers", newval);
1846}

References check_slru_buffers(), and newval.

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 2039 of file multixact.c.

2040{
2042
2043 /*
2044 * Write dirty MultiXact pages to disk. This may result in sync requests
2045 * queued for later handling by ProcessSyncRequests(), as part of the
2046 * checkpoint.
2047 */
2050
2052}
void SimpleLruWriteAll(SlruDesc *ctl, bool allow_redirtied)
Definition slru.c:1372

References fb(), MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ ExtendMultiXactMember()

static void ExtendMultiXactMember ( MultiXactOffset  offset,
int  nmembers 
)
static

Definition at line 2317 of file multixact.c.

2318{
2319 /*
2320 * It's possible that the members span more than one page of the members
2321 * file, so we loop to ensure we consider each page. The coding is not
2322 * optimal if the members span several pages, but that seems unusual
2323 * enough to not worry much about.
2324 */
2325 while (nmembers > 0)
2326 {
2327 int flagsoff;
2328 int flagsbit;
2330
2331 /*
2332 * Only zero when at first entry of a page.
2333 */
2336 if (flagsoff == 0 && flagsbit == 0)
2337 {
2338 int64 pageno;
2339 LWLock *lock;
2340
2341 pageno = MXOffsetToMemberPage(offset);
2343
2345
2346 /* Zero the page and make a WAL entry about it */
2350
2351 LWLockRelease(lock);
2352 }
2353
2354 /* Compute the number of items till end of current page. */
2356
2357 /*
2358 * Advance to next page. OK if nmembers goes negative.
2359 */
2360 nmembers -= difference;
2361 offset += difference;
2362 }
2363}
int64_t int64
Definition c.h:621
uint32_t uint32
Definition c.h:624
Datum difference(PG_FUNCTION_ARGS)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1150
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1767
@ LW_EXCLUSIVE
Definition lwlock.h:104
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
Definition multixact.h:68
static int MXOffsetToFlagsBitShift(MultiXactOffset32 offset)
static int64 MXOffsetToMemberPage(MultiXactOffset32 offset)
#define MULTIXACT_MEMBERS_PER_PAGE
static int MXOffsetToFlagsOffset(MultiXactOffset32 offset)
int SimpleLruZeroPage(SlruDesc *ctl, int64 pageno)
Definition slru.c:397
static LWLock * SimpleLruGetBankLock(SlruDesc *ctl, int64 pageno)
Definition slru.h:207
XLogRecPtr XLogSimpleInsertInt64(RmgrId rmid, uint8 info, int64 value)
Definition xloginsert.c:547

References difference(), fb(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MULTIXACT_MEMBERS_PER_PAGE, MultiXactMemberCtl, MXOffsetToFlagsBitShift(), MXOffsetToFlagsOffset(), MXOffsetToMemberPage(), SimpleLruGetBankLock(), SimpleLruZeroPage(), XLOG_MULTIXACT_ZERO_MEM_PAGE, and XLogSimpleInsertInt64().

Referenced by GetNewMultiXactId().

◆ ExtendMultiXactOffset()

static void ExtendMultiXactOffset ( MultiXactId  multi)
static

Definition at line 2283 of file multixact.c.

2284{
2285 int64 pageno;
2286 LWLock *lock;
2287
2288 /*
2289 * No work except at first MultiXactId of a page. But beware: just after
2290 * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2291 */
2292 if (MultiXactIdToOffsetEntry(multi) != 0 &&
2293 multi != FirstMultiXactId)
2294 return;
2295
2296 pageno = MultiXactIdToOffsetPage(multi);
2298
2300
2301 /* Zero the page and make a WAL entry about it */
2304 pageno);
2305
2306 LWLockRelease(lock);
2307}
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
Definition multixact.h:67
#define FirstMultiXactId
Definition multixact.h:26
static int MultiXactIdToOffsetEntry(MultiXactId multi)
static int64 MultiXactIdToOffsetPage(MultiXactId multi)

References fb(), FirstMultiXactId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdToOffsetEntry(), MultiXactIdToOffsetPage(), MultiXactOffsetCtl, SimpleLruGetBankLock(), SimpleLruZeroPage(), XLOG_MULTIXACT_ZERO_OFF_PAGE, and XLogSimpleInsertInt64().

Referenced by GetNewMultiXactId().

◆ find_multixact_start()

static bool find_multixact_start ( MultiXactId  multi,
MultiXactOffset result 
)
static

Definition at line 2503 of file multixact.c.

2504{
2505 MultiXactOffset offset;
2506 int64 pageno;
2507 int entryno;
2508 int slotno;
2510
2512
2513 pageno = MultiXactIdToOffsetPage(multi);
2515
2516 /*
2517 * Write out dirty data, so PhysicalPageExists can work correctly.
2518 */
2521
2523 return false;
2524
2525 /* lock is acquired by SimpleLruReadPage_ReadOnly */
2527 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2528 offptr += entryno;
2529 offset = *offptr;
2531
2532 *result = offset;
2533 return true;
2534}
#define Assert(condition)
Definition c.h:943
uint64 MultiXactOffset
Definition c.h:748
uint32 result
static MultiXactStateData * MultiXactState
Definition multixact.c:225
int SimpleLruReadPage_ReadOnly(SlruDesc *ctl, int64 pageno, const void *opaque_data)
Definition slru.c:654
bool SimpleLruDoesPhysicalPageExist(SlruDesc *ctl, int64 pageno)
Definition slru.c:795

References Assert, fb(), MultiXactStateData::finishedStartup, LWLockRelease(), MultiXactIdToOffsetEntry(), MultiXactIdToOffsetPage(), MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactState, result, SimpleLruDoesPhysicalPageExist(), SimpleLruGetBankLock(), SimpleLruReadPage_ReadOnly(), and SimpleLruWriteAll().

Referenced by SetOldestOffset(), and TruncateMultiXact().

◆ GetMultiXactIdMembers()

int GetMultiXactIdMembers ( MultiXactId  multi,
MultiXactMember **  members,
bool  from_pgupgrade,
bool  isLockOnly 
)

Definition at line 1172 of file multixact.c.

1174{
1175 int64 pageno;
1177 int entryno;
1178 int slotno;
1180 MultiXactOffset offset;
1182 int length;
1184 MultiXactId nextMXact;
1185 MultiXactMember *ptr;
1186 LWLock *lock;
1187
1188 debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
1189
1190 if (!MultiXactIdIsValid(multi) || from_pgupgrade)
1191 {
1192 *members = NULL;
1193 return -1;
1194 }
1195
1196 /* See if the MultiXactId is in the local cache */
1197 length = mXactCacheGetById(multi, members);
1198 if (length >= 0)
1199 {
1200 debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
1201 mxid_to_string(multi, length, *members));
1202 return length;
1203 }
1204
1205 /* Set our OldestVisibleMXactId[] entry if we didn't already */
1207
1208 /*
1209 * If we know the multi is used only for locking and not for updates, then
1210 * we can skip checking if the value is older than our oldest visible
1211 * multi. It cannot possibly still be running.
1212 */
1213 if (isLockOnly &&
1215 {
1216 debug_elog2(DEBUG2, "GetMembers: a locker-only multi is too old");
1217 *members = NULL;
1218 return -1;
1219 }
1220
1221 /*
1222 * We check known limits on MultiXact before resorting to the SLRU area.
1223 *
1224 * An ID older than MultiXactState->oldestMultiXactId cannot possibly be
1225 * useful; it has already been removed, or will be removed shortly, by
1226 * truncation. If one is passed, an error is raised.
1227 *
1228 * Also, an ID >= nextMXact shouldn't ever be seen here; if it is seen, it
1229 * implies undetected ID wraparound has occurred. This raises a hard
1230 * error.
1231 *
1232 * Shared lock is enough here since we aren't modifying any global state.
1233 * Acquire it just long enough to grab the current counter values.
1234 */
1236
1238 nextMXact = MultiXactState->nextMXact;
1239
1241
1242 if (MultiXactIdPrecedes(multi, oldestMXact))
1243 ereport(ERROR,
1245 errmsg("MultiXactId %u does no longer exist -- apparent wraparound",
1246 multi)));
1247
1248 if (!MultiXactIdPrecedes(multi, nextMXact))
1249 ereport(ERROR,
1251 errmsg("MultiXactId %u has not been created yet -- apparent wraparound",
1252 multi)));
1253
1254 /*
1255 * Find out the offset at which we need to start reading MultiXactMembers
1256 * and the number of members in the multixact. We determine the latter as
1257 * the difference between this multixact's starting offset and the next
1258 * one's.
1259 */
1260 pageno = MultiXactIdToOffsetPage(multi);
1262
1263 /* Acquire the bank lock for the page we need. */
1266
1267 /* read this multi's offset */
1268 slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, &multi);
1269 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1270 offptr += entryno;
1271 offset = *offptr;
1272
1273 if (offset == 0)
1274 ereport(ERROR,
1276 errmsg("MultiXact %u has invalid offset", multi)));
1277
1278 /* read next multi's offset */
1279 {
1281
1282 /* handle wraparound if needed */
1283 tmpMXact = NextMultiXactId(multi);
1284
1285 prev_pageno = pageno;
1286
1289
1290 if (pageno != prev_pageno)
1291 {
1292 LWLock *newlock;
1293
1294 /*
1295 * Since we're going to access a different SLRU page, if this page
1296 * falls under a different bank, release the old bank's lock and
1297 * acquire the lock of the new bank.
1298 */
1300 if (newlock != lock)
1301 {
1302 LWLockRelease(lock);
1304 lock = newlock;
1305 }
1307 }
1308
1309 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1310 offptr += entryno;
1312 }
1313
1314 LWLockRelease(lock);
1315 lock = NULL;
1316
1317 /* Sanity check the next offset */
1318 if (nextMXOffset == 0)
1319 ereport(ERROR,
1321 errmsg("MultiXact %u has invalid next offset", multi)));
1322 if (nextMXOffset == offset)
1323 ereport(ERROR,
1325 errmsg("MultiXact %u with offset (%" PRIu64 ") has zero members",
1326 multi, offset)));
1327 if (nextMXOffset < offset)
1328 ereport(ERROR,
1330 errmsg("MultiXact %u has offset (%" PRIu64 ") greater than its next offset (%" PRIu64 ")",
1331 multi, offset, nextMXOffset)));
1332 if (nextMXOffset - offset > INT32_MAX)
1333 ereport(ERROR,
1335 errmsg("MultiXact %u has too many members (%" PRIu64 ")",
1336 multi, nextMXOffset - offset)));
1337 length = nextMXOffset - offset;
1338
1339 /* read the members */
1340 ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
1341 prev_pageno = -1;
1342 for (int i = 0; i < length; i++, offset++)
1343 {
1346 int flagsoff;
1347 int bshift;
1348 int memberoff;
1349
1350 pageno = MXOffsetToMemberPage(offset);
1352
1353 if (pageno != prev_pageno)
1354 {
1356 LWLock *newlock;
1357
1358 /*
1359 * Since we're going to access a different SLRU page, if this page
1360 * falls under a different bank, release the old bank's lock and
1361 * acquire the lock of the new bank.
1362 */
1364 if (newlock != lock)
1365 {
1366 if (lock)
1367 LWLockRelease(lock);
1369 lock = newlock;
1370 }
1373 prev_pageno = pageno;
1374 }
1375
1377 (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
1379
1382 flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
1383
1384 ptr[i].xid = *xactptr;
1386 }
1387
1388 LWLockRelease(lock);
1389
1390 /*
1391 * Copy the result into the local cache.
1392 */
1393 mXactCachePut(multi, length, ptr);
1394
1395 debug_elog3(DEBUG2, "GetMembers: no cache for %s",
1396 mxid_to_string(multi, length, ptr));
1397 *members = ptr;
1398 return length;
1399}
uint32 TransactionId
Definition c.h:736
int errcode(int sqlerrcode)
Definition elog.c:874
#define DEBUG2
Definition elog.h:30
#define ERROR
Definition elog.h:40
#define ereport(elevel,...)
Definition elog.h:152
int i
Definition isn.c:77
@ LW_SHARED
Definition lwlock.h:105
void * palloc(Size size)
Definition mcxt.c:1387
static int mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
Definition multixact.c:1482
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition multixact.c:2865
static void MultiXactIdSetOldestVisible(void)
Definition multixact.c:646
static void mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition multixact.c:1529
static MultiXactId NextMultiXactId(MultiXactId multi)
Definition multixact.c:103
#define debug_elog3(a, b, c)
Definition multixact.c:311
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition multixact.c:1597
#define debug_elog2(a, b)
Definition multixact.c:310
#define MXACT_MEMBER_XACT_BITMASK
static int MXOffsetToMemberOffset(MultiXactOffset32 offset)
static char * errmsg
#define ERRCODE_DATA_CORRUPTED
int SimpleLruReadPage(SlruDesc *ctl, int64 pageno, bool write_ok, const void *opaque_data)
Definition slru.c:550
TransactionId xid
Definition multixact.h:57
MultiXactStatus status
Definition multixact.h:58
MultiXactId nextMXact
Definition multixact.c:138
MultiXactId oldestMultiXactId
Definition multixact.c:151
#define TransactionIdIsValid(xid)
Definition transam.h:41

References Assert, DEBUG2, debug_elog2, debug_elog3, ereport, errcode(), ERRCODE_DATA_CORRUPTED, errmsg, ERROR, fb(), i, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactIdSetOldestVisible(), MultiXactIdToOffsetEntry(), MultiXactIdToOffsetPage(), MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactState, MXACT_MEMBER_XACT_BITMASK, mXactCacheGetById(), mXactCachePut(), mxid_to_string(), MXOffsetToFlagsBitShift(), MXOffsetToFlagsOffset(), MXOffsetToMemberOffset(), MXOffsetToMemberPage(), MyOldestVisibleMXactIdSlot(), NextMultiXactId(), MultiXactStateData::nextMXact, MultiXactStateData::oldestMultiXactId, palloc(), SimpleLruGetBankLock(), SimpleLruReadPage(), MultiXactMember::status, TransactionIdIsValid, and MultiXactMember::xid.

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

◆ GetMultiXactInfo()

void GetMultiXactInfo ( uint32 multixacts,
MultiXactOffset nextOffset,
MultiXactId oldestMultiXactId,
MultiXactOffset oldestOffset 
)

◆ GetNewMultiXactId()

static MultiXactId GetNewMultiXactId ( int  nmembers,
MultiXactOffset offset 
)
static

Definition at line 979 of file multixact.c.

980{
982 MultiXactOffset nextOffset;
983
984 debug_elog3(DEBUG2, "GetNew: for %d xids", nmembers);
985
986 /* safety check, we should never get this far in a HS standby */
987 if (RecoveryInProgress())
988 elog(ERROR, "cannot assign MultiXactIds during recovery");
989
991
992 /* Assign the MXID */
994
995 /*----------
996 * Check to see if it's safe to assign another MultiXactId. This protects
997 * against catastrophic data loss due to multixact wraparound. The basic
998 * rules are:
999 *
1000 * If we're past multiVacLimit or the safe threshold for member storage
1001 * space, or we don't know what the safe threshold for member storage is,
1002 * start trying to force autovacuum cycles.
1003 * If we're past multiWarnLimit, start issuing warnings.
1004 * If we're past multiStopLimit, refuse to create new MultiXactIds.
1005 *
1006 * Note these are pretty much the same protections in GetNewTransactionId.
1007 *----------
1008 */
1010 {
1011 /*
1012 * For safety's sake, we release MultiXactGenLock while sending
1013 * signals, warnings, etc. This is not so much because we care about
1014 * preserving concurrency in this situation, as to avoid any
1015 * possibility of deadlock while doing get_database_name(). First,
1016 * copy all the shared values we'll need in this path.
1017 */
1018 MultiXactId multiWarnLimit = MultiXactState->multiWarnLimit;
1019 MultiXactId multiStopLimit = MultiXactState->multiStopLimit;
1020 MultiXactId multiWrapLimit = MultiXactState->multiWrapLimit;
1022
1024
1025 if (IsUnderPostmaster &&
1026 !MultiXactIdPrecedes(result, multiStopLimit))
1027 {
1029
1030 /*
1031 * Immediately kick autovacuum into action as we're already in
1032 * ERROR territory.
1033 */
1035
1036 /* complain even if that DB has disappeared */
1037 if (oldest_datname)
1038 ereport(ERROR,
1040 errmsg("database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database \"%s\"",
1042 errhint("Execute a database-wide VACUUM in that database.\n"
1043 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1044 else
1045 ereport(ERROR,
1047 errmsg("database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database with OID %u",
1049 errhint("Execute a database-wide VACUUM in that database.\n"
1050 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1051 }
1052
1053 /*
1054 * To avoid swamping the postmaster with signals, we issue the autovac
1055 * request only once per 64K multis generated. This still gives
1056 * plenty of chances before we get into real trouble.
1057 */
1058 if (IsUnderPostmaster && ((result % 65536) == 0 || result == FirstMultiXactId))
1060
1061 if (!MultiXactIdPrecedes(result, multiWarnLimit))
1062 {
1064
1065 /* complain even if that DB has disappeared */
1066 if (oldest_datname)
1068 (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
1069 "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
1070 multiWrapLimit - result,
1072 multiWrapLimit - result),
1073 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
1074 (double) (multiWrapLimit - result) / (MaxMultiXactId / 2) * 100),
1075 errhint("Execute a database-wide VACUUM in that database.\n"
1076 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1077 else
1079 (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
1080 "database with OID %u must be vacuumed before %u more MultiXactIds are used",
1081 multiWrapLimit - result,
1083 multiWrapLimit - result),
1084 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
1085 (double) (multiWrapLimit - result) / (MaxMultiXactId / 2) * 100),
1086 errhint("Execute a database-wide VACUUM in that database.\n"
1087 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1088 }
1089
1090 /* Re-acquire lock and start over */
1093 }
1094
1095 /*
1096 * Make sure there is room for the next MXID in the file. Assigning this
1097 * MXID sets the next MXID's offset already.
1098 */
1100
1101 /*
1102 * Reserve the members space, similarly to above.
1103 */
1104 nextOffset = MultiXactState->nextOffset;
1105
1106 /*
1107 * Offsets are 64-bit integers and will never wrap around. Firstly, it
1108 * would take an unrealistic amount of time and resources to consume 2^64
1109 * offsets. Secondly, multixid creation is WAL-logged, so you would run
1110 * out of LSNs before reaching offset wraparound. Nevertheless, check for
1111 * wraparound as a sanity check.
1112 */
1113 if (nextOffset + nmembers < nextOffset)
1114 ereport(ERROR,
1116 errmsg("MultiXact members would wrap around")));
1117 *offset = nextOffset;
1118
1119 ExtendMultiXactMember(nextOffset, nmembers);
1120
1121 /*
1122 * Critical section from here until caller has written the data into the
1123 * just-reserved SLRU space; we don't want to error out with a partly
1124 * written MultiXact structure. (In particular, failing to write our
1125 * start offset after advancing nextMXact would effectively corrupt the
1126 * previous MultiXact.)
1127 */
1129
1130 /*
1131 * Advance counters. As in GetNewTransactionId(), this must not happen
1132 * until after file extension has succeeded!
1133 */
1135 MultiXactState->nextOffset += nmembers;
1136
1138
1139 debug_elog4(DEBUG2, "GetNew: returning %u offset %" PRIu64,
1140 result, *offset);
1141 return result;
1142}
int errhint(const char *fmt,...) pg_attribute_printf(1
int errdetail(const char *fmt,...) pg_attribute_printf(1
#define WARNING
Definition elog.h:37
int int int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...) pg_attribute_printf(1
#define elog(elevel,...)
Definition elog.h:228
bool IsUnderPostmaster
Definition globals.c:122
char * get_database_name(Oid dbid)
Definition lsyscache.c:1312
#define START_CRIT_SECTION()
Definition miscadmin.h:152
static void ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
Definition multixact.c:2317
static void ExtendMultiXactOffset(MultiXactId multi)
Definition multixact.c:2283
#define debug_elog4(a, b, c, d)
Definition multixact.c:312
#define MaxMultiXactId
Definition multixact.h:27
void SendPostmasterSignal(PMSignalReason reason)
Definition pmsignal.c:164
@ PMSIGNAL_START_AUTOVAC_LAUNCHER
Definition pmsignal.h:39
unsigned int Oid
MultiXactId multiWrapLimit
Definition multixact.c:164
MultiXactId multiStopLimit
Definition multixact.c:163
MultiXactId multiWarnLimit
Definition multixact.c:162
MultiXactId multiVacLimit
Definition multixact.c:161
bool RecoveryInProgress(void)
Definition xlog.c:6830

References DEBUG2, debug_elog3, debug_elog4, elog, ereport, errcode(), errdetail(), errhint(), errmsg, errmsg_plural(), ERROR, ExtendMultiXactMember(), ExtendMultiXactOffset(), fb(), FirstMultiXactId, get_database_name(), IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaxMultiXactId, MultiXactStateData::multiStopLimit, MultiXactStateData::multiVacLimit, MultiXactStateData::multiWarnLimit, MultiXactStateData::multiWrapLimit, MultiXactIdPrecedes(), MultiXactState, NextMultiXactId(), MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactDB, PMSIGNAL_START_AUTOVAC_LAUNCHER, RecoveryInProgress(), result, SendPostmasterSignal(), START_CRIT_SECTION, and WARNING.

Referenced by MultiXactIdCreateFromMembers().

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2378 of file multixact.c.

2379{
2381
2382 /*
2383 * This is the oldest valid value among all the OldestMemberMXactId[] and
2384 * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2385 */
2388 for (int i = 0; i < NumMemberSlots; i++)
2389 {
2391
2396 }
2397 for (int i = 0; i < NumVisibleSlots; i++)
2398 {
2400
2405 }
2406
2408
2409 return oldestMXact;
2410}
#define NumMemberSlots
Definition multixact.c:221
static MultiXactId * OldestVisibleMXactId
Definition multixact.c:227
static MultiXactId * OldestMemberMXactId
Definition multixact.c:226
#define NumVisibleSlots
Definition multixact.c:222

References fb(), i, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactState, MultiXactStateData::nextMXact, NumMemberSlots, NumVisibleSlots, OldestMemberMXactId, and OldestVisibleMXactId.

Referenced by heapam_relation_set_new_filelocator(), vac_update_datfrozenxid(), and vacuum_get_cutoffs().

◆ multixact_redo()

void multixact_redo ( XLogReaderState record)

Definition at line 2915 of file multixact.c.

2916{
2917 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2918
2919 /* Backup blocks are not used in multixact records */
2921
2922 if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
2923 {
2924 int64 pageno;
2925
2926 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
2928 }
2929 else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
2930 {
2931 int64 pageno;
2932
2933 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
2935 }
2936 else if (info == XLOG_MULTIXACT_CREATE_ID)
2937 {
2941 int i;
2942
2943 /* Store the data back into the SLRU files */
2944 RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
2945 xlrec->members);
2946
2947 /* Make sure nextMXact/nextOffset are beyond what this record has */
2949 xlrec->moff + xlrec->nmembers);
2950
2951 /*
2952 * Make sure nextXid is beyond any XID mentioned in the record. This
2953 * should be unnecessary, since any XID found here ought to have other
2954 * evidence in the XLOG, but let's be safe.
2955 */
2956 max_xid = XLogRecGetXid(record);
2957 for (i = 0; i < xlrec->nmembers; i++)
2958 {
2959 if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
2960 max_xid = xlrec->members[i].xid;
2961 }
2962
2964 }
2965 else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
2966 {
2968
2969 memcpy(&xlrec, XLogRecGetData(record),
2971
2972 elog(DEBUG1, "replaying multixact truncation: "
2973 "oldestMulti %u (offsets segment %" PRIx64 "), "
2974 "oldestOffset %" PRIu64 " (members segment %" PRIx64 ")",
2975 xlrec.oldestMulti,
2976 MultiXactIdToOffsetSegment(xlrec.oldestMulti),
2977 xlrec.oldestOffset,
2978 MXOffsetToMemberSegment(xlrec.oldestOffset));
2979
2980 /* should not be required, but more than cheap enough */
2982
2983 /*
2984 * Advance the horizon values, so they're current at the end of
2985 * recovery.
2986 */
2987 SetMultiXactIdLimit(xlrec.oldestMulti, xlrec.oldestMultiDB);
2988
2989 PerformMembersTruncation(xlrec.oldestOffset);
2990 PerformOffsetsTruncation(xlrec.oldestMulti);
2991
2993 }
2994 else
2995 elog(PANIC, "multixact_redo: unknown op code %u", info);
2996}
uint8_t uint8
Definition c.h:622
memcpy(sums, checksumBaseOffsets, sizeof(checksumBaseOffsets))
#define PANIC
Definition elog.h:44
#define DEBUG1
Definition elog.h:31
static void PerformOffsetsTruncation(MultiXactId newOldestMulti)
Definition multixact.c:2653
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition multixact.c:816
static void PerformMembersTruncation(MultiXactOffset newOldestOffset)
Definition multixact.c:2643
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition multixact.c:2239
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
Definition multixact.c:2085
#define XLOG_MULTIXACT_TRUNCATE_ID
Definition multixact.h:70
#define SizeOfMultiXactTruncate
Definition multixact.h:93
#define XLOG_MULTIXACT_CREATE_ID
Definition multixact.h:69
static int64 MultiXactIdToOffsetSegment(MultiXactId multi)
static int64 MXOffsetToMemberSegment(MultiXactOffset offset)
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
Definition transam.h:263
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
Definition varsup.c:299
#define XLogRecGetInfo(decoder)
Definition xlogreader.h:410
#define XLogRecGetData(decoder)
Definition xlogreader.h:415
#define XLogRecGetXid(decoder)
Definition xlogreader.h:412
#define XLogRecHasAnyBlockRefs(decoder)
Definition xlogreader.h:417

References AdvanceNextFullTransactionIdPastXid(), Assert, DEBUG1, elog, fb(), i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), memcpy(), MultiXactAdvanceNextMXact(), MultiXactIdToOffsetSegment(), MultiXactMemberCtl, MultiXactOffsetCtl, MXOffsetToMemberSegment(), NextMultiXactId(), PANIC, PerformMembersTruncation(), PerformOffsetsTruncation(), RecordNewMultiXact(), SetMultiXactIdLimit(), SimpleLruZeroAndWritePage(), SizeOfMultiXactTruncate, TransactionIdPrecedes(), XLOG_MULTIXACT_CREATE_ID, XLOG_MULTIXACT_TRUNCATE_ID, XLOG_MULTIXACT_ZERO_MEM_PAGE, XLOG_MULTIXACT_ZERO_OFF_PAGE, XLogRecGetData, XLogRecGetInfo, XLogRecGetXid, and XLogRecHasAnyBlockRefs.

◆ multixact_twophase_postabort()

void multixact_twophase_postabort ( FullTransactionId  fxid,
uint16  info,
void recdata,
uint32  len 
)

Definition at line 1755 of file multixact.c.

1757{
1759}
void multixact_twophase_postcommit(FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
Definition multixact.c:1740
const void size_t len

References fb(), len, and multixact_twophase_postcommit().

◆ multixact_twophase_postcommit()

void multixact_twophase_postcommit ( FullTransactionId  fxid,
uint16  info,
void recdata,
uint32  len 
)

Definition at line 1740 of file multixact.c.

1742{
1744
1745 Assert(len == sizeof(MultiXactId));
1746
1748}
static MultiXactId * PreparedXactOldestMemberMXactIdSlot(ProcNumber procno)
Definition multixact.c:252
int ProcNumber
Definition procnumber.h:24
ProcNumber TwoPhaseGetDummyProcNumber(FullTransactionId fxid, bool lock_held)
Definition twophase.c:914

References Assert, fb(), InvalidMultiXactId, len, PreparedXactOldestMemberMXactIdSlot(), and TwoPhaseGetDummyProcNumber().

Referenced by multixact_twophase_postabort().

◆ multixact_twophase_recover()

void multixact_twophase_recover ( FullTransactionId  fxid,
uint16  info,
void recdata,
uint32  len 
)

Definition at line 1719 of file multixact.c.

1721{
1724
1725 /*
1726 * Get the oldest member XID from the state file record, and set it in the
1727 * OldestMemberMXactId slot reserved for this prepared transaction.
1728 */
1729 Assert(len == sizeof(MultiXactId));
1731
1733}

References Assert, fb(), len, PreparedXactOldestMemberMXactIdSlot(), and TwoPhaseGetDummyProcNumber().

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

◆ MultiXactAdvanceOldest()

void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2266 of file multixact.c.

2267{
2269
2271 SetMultiXactIdLimit(oldestMulti, oldestMultiDB);
2272}
bool InRecovery
Definition xlogutils.c:50

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

Referenced by xlog_redo().

◆ MultiXactGetCheckptMulti()

void MultiXactGetCheckptMulti ( bool  is_shutdown,
MultiXactId nextMulti,
MultiXactOffset nextMultiOffset,
MultiXactId oldestMulti,
Oid oldestMultiDB 
)

Definition at line 2017 of file multixact.c.

2022{
2024 *nextMulti = MultiXactState->nextMXact;
2025 *nextMultiOffset = MultiXactState->nextOffset;
2026 *oldestMulti = MultiXactState->oldestMultiXactId;
2027 *oldestMultiDB = MultiXactState->oldestMultiXactDB;
2029
2031 "MultiXact: checkpoint is nextMulti %u, nextOffset %" PRIu64 ", oldestMulti %u in DB %u",
2032 *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
2033}
#define debug_elog6(a, b, c, d, e, f)
Definition multixact.c:314

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

Referenced by CreateCheckPoint().

◆ MultiXactIdCreate()

MultiXactId MultiXactIdCreate ( TransactionId  xid1,
MultiXactStatus  status1,
TransactionId  xid2,
MultiXactStatus  status2 
)

Definition at line 358 of file multixact.c.

360{
362 MultiXactMember members[2];
363
366
368
369 /* MultiXactIdSetOldestMember() must have been called already. */
371
372 /*
373 * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs
374 * are still running. In typical usage, xid2 will be our own XID and the
375 * caller just did a check on xid1, so it'd be wasted effort.
376 */
377
378 members[0].xid = xid1;
379 members[0].status = status1;
380 members[1].xid = xid2;
381 members[1].status = status2;
382
384
385 debug_elog3(DEBUG2, "Create: %s",
386 mxid_to_string(newMulti, 2, members));
387
388 return newMulti;
389}
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition multixact.c:715
#define TransactionIdEquals(id1, id2)
Definition transam.h:43

References Assert, DEBUG2, debug_elog3, fb(), MultiXactIdCreateFromMembers(), MultiXactIdIsValid, mxid_to_string(), MyOldestMemberMXactIdSlot(), MultiXactMember::status, TransactionIdEquals, TransactionIdIsValid, and MultiXactMember::xid.

Referenced by compute_new_xmax_infomask(), and test_create_multixact().

◆ MultiXactIdCreateFromMembers()

MultiXactId MultiXactIdCreateFromMembers ( int  nmembers,
MultiXactMember members 
)

Definition at line 715 of file multixact.c.

716{
717 MultiXactId multi;
718 MultiXactOffset offset;
720
721 debug_elog3(DEBUG2, "Create: %s",
722 mxid_to_string(InvalidMultiXactId, nmembers, members));
723
724 /*
725 * See if the same set of members already exists in our cache; if so, just
726 * re-use that MultiXactId. (Note: it might seem that looking in our
727 * cache is insufficient, and we ought to search disk to see if a
728 * duplicate definition already exists. But since we only ever create
729 * MultiXacts containing our own XID, in most cases any such MultiXacts
730 * were in fact created by us, and so will be in our cache. There are
731 * corner cases where someone else added us to a MultiXact without our
732 * knowledge, but it's not worth checking for.)
733 */
734 multi = mXactCacheGetBySet(nmembers, members);
735 if (MultiXactIdIsValid(multi))
736 {
737 debug_elog2(DEBUG2, "Create: in cache!");
738 return multi;
739 }
740
741 /* Verify that there is a single update Xid among the given members. */
742 {
743 int i;
744 bool has_update = false;
745
746 for (i = 0; i < nmembers; i++)
747 {
748 if (ISUPDATE_from_mxstatus(members[i].status))
749 {
750 if (has_update)
751 elog(ERROR, "new multixact has more than one updating member: %s",
752 mxid_to_string(InvalidMultiXactId, nmembers, members));
753 has_update = true;
754 }
755 }
756 }
757
758 /* Load the injection point before entering the critical section */
759 INJECTION_POINT_LOAD("multixact-create-from-members");
760
761 /*
762 * Assign the MXID and offsets range to use, and make sure there is space
763 * in the OFFSETs and MEMBERs files. NB: this routine does
764 * START_CRIT_SECTION().
765 *
766 * Note: unlike MultiXactIdCreate and MultiXactIdExpand, we do not check
767 * that we've called MultiXactIdSetOldestMember here. This is because
768 * this routine is used in some places to create new MultiXactIds of which
769 * the current backend is not a member, notably during freezing of multis
770 * in vacuum. During vacuum, in particular, it would be unacceptable to
771 * keep OldestMulti set, in case it runs for long.
772 */
773 multi = GetNewMultiXactId(nmembers, &offset);
774
775 INJECTION_POINT_CACHED("multixact-create-from-members", NULL);
776
777 /* Make an XLOG entry describing the new MXID. */
778 xlrec.mid = multi;
779 xlrec.moff = offset;
780 xlrec.nmembers = nmembers;
781
782 /*
783 * XXX Note: there's a lot of padding space in MultiXactMember. We could
784 * find a more compact representation of this Xlog record -- perhaps all
785 * the status flags in one XLogRecData, then all the xids in another one?
786 * Not clear that it's worth the trouble though.
787 */
790 XLogRegisterData(members, nmembers * sizeof(MultiXactMember));
791
793
794 /* Now enter the information into the OFFSETs and MEMBERs logs */
795 RecordNewMultiXact(multi, offset, nmembers, members);
796
797 /* Done with critical section */
799
800 /* Store the new MultiXactId in the local cache, too */
801 mXactCachePut(multi, nmembers, members);
802
803 debug_elog2(DEBUG2, "Create: all done");
804
805 return multi;
806}
#define INJECTION_POINT_CACHED(name, arg)
#define INJECTION_POINT_LOAD(name)
#define END_CRIT_SECTION()
Definition miscadmin.h:154
static MultiXactId GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
Definition multixact.c:979
static MultiXactId mXactCacheGetBySet(int nmembers, MultiXactMember *members)
Definition multixact.c:1439
#define ISUPDATE_from_mxstatus(status)
Definition multixact.h:51
#define SizeOfMultiXactCreate
Definition multixact.h:80
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:482
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:372
void XLogBeginInsert(void)
Definition xloginsert.c:153

References DEBUG2, debug_elog2, debug_elog3, elog, END_CRIT_SECTION, ERROR, fb(), GetNewMultiXactId(), i, INJECTION_POINT_CACHED, INJECTION_POINT_LOAD, InvalidMultiXactId, ISUPDATE_from_mxstatus, MultiXactIdIsValid, mXactCacheGetBySet(), mXactCachePut(), mxid_to_string(), RecordNewMultiXact(), SizeOfMultiXactCreate, XLOG_MULTIXACT_CREATE_ID, XLogBeginInsert(), XLogInsert(), and XLogRegisterData().

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

◆ MultiXactIdExpand()

MultiXactId MultiXactIdExpand ( MultiXactId  multi,
TransactionId  xid,
MultiXactStatus  status 
)

Definition at line 411 of file multixact.c.

412{
414 MultiXactMember *members;
416 int nmembers;
417 int i;
418 int j;
419
422
423 /* MultiXactIdSetOldestMember() must have been called already. */
425
426 debug_elog5(DEBUG2, "Expand: received multi %u, xid %u status %s",
427 multi, xid, mxstatus_to_string(status));
428
429 /*
430 * Note: we don't allow for old multis here. The reason is that the only
431 * caller of this function does a check that the multixact is no longer
432 * running.
433 */
434 nmembers = GetMultiXactIdMembers(multi, &members, false, false);
435
436 if (nmembers < 0)
437 {
438 MultiXactMember member;
439
440 /*
441 * The MultiXactId is obsolete. This can only happen if all the
442 * MultiXactId members stop running between the caller checking and
443 * passing it to us. It would be better to return that fact to the
444 * caller, but it would complicate the API and it's unlikely to happen
445 * too often, so just deal with it by creating a singleton MultiXact.
446 */
447 member.xid = xid;
448 member.status = status;
450
451 debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u",
452 multi, newMulti);
453 return newMulti;
454 }
455
456 /*
457 * If the TransactionId is already a member of the MultiXactId with the
458 * same status, just return the existing MultiXactId.
459 */
460 for (i = 0; i < nmembers; i++)
461 {
462 if (TransactionIdEquals(members[i].xid, xid) &&
463 (members[i].status == status))
464 {
465 debug_elog4(DEBUG2, "Expand: %u is already a member of %u",
466 xid, multi);
467 pfree(members);
468 return multi;
469 }
470 }
471
472 /*
473 * Determine which of the members of the MultiXactId are still of
474 * interest. This is any running transaction, and also any transaction
475 * that grabbed something stronger than just a lock and was committed. (An
476 * update that aborted is of no interest here; and having more than one
477 * update Xid in a multixact would cause errors elsewhere.)
478 *
479 * Removing dead members is not just an optimization: freezing of tuples
480 * whose Xmax are multis depends on this behavior.
481 *
482 * Note we have the same race condition here as above: j could be 0 at the
483 * end of the loop.
484 */
485 newMembers = palloc_array(MultiXactMember, nmembers + 1);
486
487 for (i = 0, j = 0; i < nmembers; i++)
488 {
489 if (TransactionIdIsInProgress(members[i].xid) ||
490 (ISUPDATE_from_mxstatus(members[i].status) &&
491 TransactionIdDidCommit(members[i].xid)))
492 {
493 newMembers[j].xid = members[i].xid;
494 newMembers[j++].status = members[i].status;
495 }
496 }
497
498 newMembers[j].xid = xid;
499 newMembers[j++].status = status;
501
502 pfree(members);
504
505 debug_elog3(DEBUG2, "Expand: returning new multi %u", newMulti);
506
507 return newMulti;
508}
#define palloc_array(type, count)
Definition fe_memutils.h:76
int j
Definition isn.c:78
void pfree(void *pointer)
Definition mcxt.c:1616
char * mxstatus_to_string(MultiXactStatus status)
Definition multixact.c:1574
#define debug_elog5(a, b, c, d, e)
Definition multixact.c:313
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool isLockOnly)
Definition multixact.c:1172
bool TransactionIdIsInProgress(TransactionId xid)
Definition procarray.c:1393
bool TransactionIdDidCommit(TransactionId transactionId)
Definition transam.c:126

References Assert, DEBUG2, debug_elog3, debug_elog4, debug_elog5, fb(), GetMultiXactIdMembers(), i, ISUPDATE_from_mxstatus, j, MultiXactIdCreateFromMembers(), MultiXactIdIsValid, mxstatus_to_string(), MyOldestMemberMXactIdSlot(), palloc_array, pfree(), MultiXactMember::status, TransactionIdDidCommit(), TransactionIdEquals, TransactionIdIsInProgress(), TransactionIdIsValid, and MultiXactMember::xid.

Referenced by compute_new_xmax_infomask().

◆ MultiXactIdIsRunning()

bool MultiXactIdIsRunning ( MultiXactId  multi,
bool  isLockOnly 
)

Definition at line 522 of file multixact.c.

523{
524 MultiXactMember *members;
525 int nmembers;
526 int i;
527
528 debug_elog3(DEBUG2, "IsRunning %u?", multi);
529
530 /*
531 * "false" here means we assume our callers have checked that the given
532 * multi cannot possibly come from a pg_upgraded database.
533 */
534 nmembers = GetMultiXactIdMembers(multi, &members, false, isLockOnly);
535
536 if (nmembers <= 0)
537 {
538 debug_elog2(DEBUG2, "IsRunning: no members");
539 return false;
540 }
541
542 /*
543 * Checking for myself is cheap compared to looking in shared memory;
544 * return true if any live subtransaction of the current top-level
545 * transaction is a member.
546 *
547 * This is not needed for correctness, it's just a fast path.
548 */
549 for (i = 0; i < nmembers; i++)
550 {
551 if (TransactionIdIsCurrentTransactionId(members[i].xid))
552 {
553 debug_elog3(DEBUG2, "IsRunning: I (%d) am running!", i);
554 pfree(members);
555 return true;
556 }
557 }
558
559 /*
560 * This could be made faster by having another entry point in procarray.c,
561 * walking the PGPROC array only once for all the members. But in most
562 * cases nmembers should be small enough that it doesn't much matter.
563 */
564 for (i = 0; i < nmembers; i++)
565 {
566 if (TransactionIdIsInProgress(members[i].xid))
567 {
568 debug_elog4(DEBUG2, "IsRunning: member %d (%u) is running",
569 i, members[i].xid);
570 pfree(members);
571 return true;
572 }
573 }
574
575 pfree(members);
576
577 debug_elog3(DEBUG2, "IsRunning: %u is not running", multi);
578
579 return false;
580}
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition xact.c:943

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

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

◆ MultiXactIdPrecedes()

◆ MultiXactIdPrecedesOrEquals()

bool MultiXactIdPrecedesOrEquals ( MultiXactId  multi1,
MultiXactId  multi2 
)

Definition at line 2879 of file multixact.c.

2880{
2881 int32 diff = (int32) (multi1 - multi2);
2882
2883 return (diff <= 0);
2884}

References fb().

Referenced by check_mxid_in_range(), heap_tuple_should_freeze(), heap_vacuum_rel(), TruncateMultiXact(), and vacuum_get_cutoffs().

◆ MultiXactIdSetOldestMember()

void MultiXactIdSetOldestMember ( void  )

Definition at line 596 of file multixact.c.

597{
599 {
600 MultiXactId nextMXact;
601
602 /*
603 * You might think we don't need to acquire a lock here, since
604 * fetching and storing of TransactionIds is probably atomic, but in
605 * fact we do: suppose we pick up nextMXact and then lose the CPU for
606 * a long time. Someone else could advance nextMXact, and then
607 * another someone else could compute an OldestVisibleMXactId that
608 * would be after the value we are going to store when we get control
609 * back. Which would be wrong.
610 *
611 * Note that a shared lock is sufficient, because it's enough to stop
612 * someone from advancing nextMXact; and nobody else could be trying
613 * to write to our OldestMember entry, only reading (and we assume
614 * storing it is atomic.)
615 */
617
618 nextMXact = MultiXactState->nextMXact;
619
620 *MyOldestMemberMXactIdSlot() = nextMXact;
621
623
624 debug_elog4(DEBUG2, "MultiXact: setting OldestMember[%d] = %u",
625 MyProcNumber, nextMXact);
626 }
627}
ProcNumber MyProcNumber
Definition globals.c:92

References DEBUG2, debug_elog4, fb(), LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MultiXactState, MyOldestMemberMXactIdSlot(), MyProcNumber, and MultiXactStateData::nextMXact.

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

◆ MultiXactIdSetOldestVisible()

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2590 of file multixact.c.

2591{
2594 double fraction;
2595 int result;
2596 MultiXactId oldestMultiXactId;
2597 MultiXactOffset oldestOffset;
2598 MultiXactOffset nextOffset;
2599 uint64 members;
2600
2601 /* Read the current offsets and multixact usage. */
2602 GetMultiXactInfo(&multixacts, &nextOffset, &oldestMultiXactId, &oldestOffset);
2603 members = nextOffset - oldestOffset;
2604
2605 /* If member space utilization is low, no special action is required. */
2606 if (members <= MULTIXACT_MEMBER_LOW_THRESHOLD)
2608
2609 /*
2610 * Compute a target for relminmxid advancement. The number of multixacts
2611 * we try to eliminate from the system is based on how far we are past
2612 * MULTIXACT_MEMBER_LOW_THRESHOLD.
2613 *
2614 * The way this formula works is that when members is exactly at the low
2615 * threshold, fraction = 0.0, and we set freeze_max_age equal to
2616 * mxid_age(oldestMultiXactId). As members grows further, towards the
2617 * high threshold, fraction grows linearly from 0.0 to 1.0, and the result
2618 * shrinks from mxid_age(oldestMultiXactId) to 0. Beyond the high
2619 * threshold, fraction > 1.0 and the result is clamped to 0.
2620 */
2623
2624 /* fraction could be > 1.0, but lowest possible freeze age is zero */
2625 if (fraction >= 1.0)
2626 return 0;
2627
2630
2631 /*
2632 * Clamp to autovacuum_multixact_freeze_max_age, so that we never make
2633 * autovacuum less aggressive than it would otherwise be.
2634 */
2636}
int autovacuum_multixact_freeze_max_age
Definition autovacuum.c:136
#define Min(x, y)
Definition c.h:1091
uint64_t uint64
Definition c.h:625
void GetMultiXactInfo(uint32 *multixacts, MultiXactOffset *nextOffset, MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset)
Definition multixact.c:2546
#define MULTIXACT_MEMBER_LOW_THRESHOLD
Definition multixact.c:99
#define MULTIXACT_MEMBER_HIGH_THRESHOLD
Definition multixact.c:100

References autovacuum_multixact_freeze_max_age, fb(), GetMultiXactInfo(), Min, MULTIXACT_MEMBER_HIGH_THRESHOLD, MULTIXACT_MEMBER_LOW_THRESHOLD, and result.

Referenced by do_autovacuum(), do_start_worker(), pg_stat_get_autovacuum_scores(), and vacuum_get_cutoffs().

◆ MultiXactMemberIoErrorDetail()

static int MultiXactMemberIoErrorDetail ( const void opaque_data)
static

Definition at line 2846 of file multixact.c.

2847{
2849
2850 if (MultiXactIdIsValid(context->multi))
2851 return errdetail("Could not access member of multixact %u at offset %" PRIu64 ".",
2852 context->multi, context->offset);
2853 else
2854 return errdetail("Could not access multixact member at offset %" PRIu64 ".",
2855 context->offset);
2856}

References errdetail(), fb(), MultiXactMemberSlruReadContext::multi, MultiXactIdIsValid, and MultiXactMemberSlruReadContext::offset.

Referenced by MultiXactShmemRequest().

◆ MultiXactMemberPagePrecedes()

static bool MultiXactMemberPagePrecedes ( int64  page1,
int64  page2 
)
static

Definition at line 2832 of file multixact.c.

2833{
2834 return page1 < page2;
2835}

References fb().

Referenced by MultiXactShmemRequest().

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char path 
)

Definition at line 3011 of file multixact.c.

3012{
3013 return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
3014}
int SlruSyncFileTag(SlruDesc *ctl, const FileTag *ftag, char *path)
Definition slru.c:1884

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ MultiXactOffsetIoErrorDetail()

static int MultiXactOffsetIoErrorDetail ( const void opaque_data)
static

Definition at line 2838 of file multixact.c.

2839{
2841
2842 return errdetail("Could not access offset of multixact %u.", multixid);
2843}

References errdetail(), and fb().

Referenced by MultiXactShmemRequest().

◆ MultiXactOffsetPagePrecedes()

static bool MultiXactOffsetPagePrecedes ( int64  page1,
int64  page2 
)
static

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char path 
)

Definition at line 3002 of file multixact.c.

3003{
3004 return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
3005}

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 2063 of file multixact.c.

2065{
2066 Assert(MultiXactIdIsValid(nextMulti));
2067 debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %" PRIu64,
2068 nextMulti, nextMultiOffset);
2069
2071 MultiXactState->nextMXact = nextMulti;
2072 MultiXactState->nextOffset = nextMultiOffset;
2074}

References Assert, DEBUG2, debug_elog4, fb(), LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MultiXactState, MultiXactStateData::nextMXact, and MultiXactStateData::nextOffset.

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

◆ MultiXactShmemAttach()

static void MultiXactShmemAttach ( void arg)
static

Definition at line 1832 of file multixact.c.

1833{
1834 /* Set up array pointers */
1837}
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition multixact.c:215

References MultiXactState, NumMemberSlots, OldestMemberMXactId, OldestVisibleMXactId, and MultiXactStateData::perBackendXactIds.

◆ MultiXactShmemInit()

static void MultiXactShmemInit ( void arg)
static

Definition at line 1817 of file multixact.c.

1818{
1820
1821 /*
1822 * members SLRU doesn't call SimpleLruTruncate() or meet criteria for unit
1823 * tests
1824 */
1825
1826 /* Set up array pointers */
1829}
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition slru.h:233

References MULTIXACT_OFFSETS_PER_PAGE, MultiXactOffsetCtl, MultiXactState, NumMemberSlots, OldestMemberMXactId, OldestVisibleMXactId, MultiXactStateData::perBackendXactIds, and SlruPagePrecedesUnitTests.

◆ MultiXactShmemRequest()

static void MultiXactShmemRequest ( void arg)
static

Definition at line 1766 of file multixact.c.

1767{
1768 Size size;
1769
1770 /*
1771 * Calculate the size of the MultiXactState struct, and the two
1772 * per-backend MultiXactId arrays. They are carved out of the same
1773 * allocation.
1774 */
1775 size = offsetof(MultiXactStateData, perBackendXactIds);
1776 size = add_size(size,
1778 size = add_size(size,
1780 ShmemRequestStruct(.name = "Shared MultiXact State",
1781 .size = size,
1782 .ptr = (void **) &MultiXactState,
1783 );
1784
1786 .name = "multixact_offset",
1787 .Dir = "pg_multixact/offsets",
1788 .long_segment_names = false,
1789
1790 .nslots = multixact_offset_buffers,
1791
1792 .sync_handler = SYNC_HANDLER_MULTIXACT_OFFSET,
1793 .PagePrecedes = MultiXactOffsetPagePrecedes,
1794 .errdetail_for_io_error = MultiXactOffsetIoErrorDetail,
1795
1796 .buffer_tranche_id = LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1797 .bank_tranche_id = LWTRANCHE_MULTIXACTOFFSET_SLRU,
1798 );
1799
1801 .name = "multixact_member",
1802 .Dir = "pg_multixact/members",
1803 .long_segment_names = true,
1804
1805 .nslots = multixact_member_buffers,
1806
1807 .sync_handler = SYNC_HANDLER_MULTIXACT_MEMBER,
1808 .PagePrecedes = MultiXactMemberPagePrecedes,
1809 .errdetail_for_io_error = MultiXactMemberIoErrorDetail,
1810
1811 .buffer_tranche_id = LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1812 .bank_tranche_id = LWTRANCHE_MULTIXACTMEMBER_SLRU,
1813 );
1814}
size_t Size
Definition c.h:689
int multixact_offset_buffers
Definition globals.c:166
int multixact_member_buffers
Definition globals.c:165
static SlruDesc MultiXactMemberSlruDesc
Definition multixact.c:123
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
Definition multixact.c:2832
static SlruDesc MultiXactOffsetSlruDesc
Definition multixact.c:122
static int MultiXactOffsetIoErrorDetail(const void *opaque_data)
Definition multixact.c:2838
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition multixact.c:2811
static int MultiXactMemberIoErrorDetail(const void *opaque_data)
Definition multixact.c:2846
Size add_size(Size s1, Size s2)
Definition shmem.c:1048
Size mul_size(Size s1, Size s2)
Definition shmem.c:1063
#define ShmemRequestStruct(...)
Definition shmem.h:176
#define SimpleLruRequest(...)
Definition slru.h:218
@ SYNC_HANDLER_MULTIXACT_MEMBER
Definition sync.h:41
@ SYNC_HANDLER_MULTIXACT_OFFSET
Definition sync.h:40
const char * name

References add_size(), fb(), mul_size(), multixact_member_buffers, multixact_offset_buffers, MultiXactMemberIoErrorDetail(), MultiXactMemberPagePrecedes(), MultiXactMemberSlruDesc, MultiXactOffsetIoErrorDetail(), MultiXactOffsetPagePrecedes(), MultiXactOffsetSlruDesc, MultiXactState, name, NumMemberSlots, NumVisibleSlots, ShmemRequestStruct, SimpleLruRequest, SYNC_HANDLER_MULTIXACT_MEMBER, and SYNC_HANDLER_MULTIXACT_OFFSET.

◆ mXactCacheGetById()

static int mXactCacheGetById ( MultiXactId  multi,
MultiXactMember **  members 
)
static

Definition at line 1482 of file multixact.c.

1483{
1484 dlist_iter iter;
1485
1486 debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
1487
1489 {
1491 iter.cur);
1492
1493 if (entry->multi == multi)
1494 {
1495 MultiXactMember *ptr;
1496 Size size;
1497
1498 size = sizeof(MultiXactMember) * entry->nmembers;
1499 ptr = (MultiXactMember *) palloc(size);
1500
1501 memcpy(ptr, entry->members, size);
1502
1503 debug_elog3(DEBUG2, "CacheGet: found %s",
1504 mxid_to_string(multi,
1505 entry->nmembers,
1506 entry->members));
1507
1508 /*
1509 * Note we modify the list while not using a modifiable iterator.
1510 * This is acceptable only because we exit the iteration
1511 * immediately afterwards.
1512 */
1514
1515 *members = ptr;
1516 return entry->nmembers;
1517 }
1518 }
1519
1520 debug_elog2(DEBUG2, "CacheGet: not found");
1521 return -1;
1522}
#define dclist_container(type, membername, ptr)
Definition ilist.h:947
static void dclist_move_head(dclist_head *head, dlist_node *node)
Definition ilist.h:808
#define dclist_foreach(iter, lhead)
Definition ilist.h:970
dlist_node * cur
Definition ilist.h:179
MultiXactId multi
Definition multixact.c:293
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition multixact.c:296

References dlist_iter::cur, dclist_container, dclist_foreach, dclist_move_head(), DEBUG2, debug_elog2, debug_elog3, mXactCacheEnt::members, memcpy(), mXactCacheEnt::multi, MXactCache, mxid_to_string(), mXactCacheEnt::nmembers, and palloc().

Referenced by GetMultiXactIdMembers().

◆ mXactCacheGetBySet()

static MultiXactId mXactCacheGetBySet ( int  nmembers,
MultiXactMember members 
)
static

Definition at line 1439 of file multixact.c.

1440{
1441 dlist_iter iter;
1442
1443 debug_elog3(DEBUG2, "CacheGet: looking for %s",
1444 mxid_to_string(InvalidMultiXactId, nmembers, members));
1445
1446 /* sort the array so comparison is easy */
1447 qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1448
1450 {
1452 iter.cur);
1453
1454 if (entry->nmembers != nmembers)
1455 continue;
1456
1457 /*
1458 * We assume the cache entries are sorted, and that the unused bits in
1459 * "status" are zeroed.
1460 */
1461 if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
1462 {
1463 debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
1465 return entry->multi;
1466 }
1467 }
1468
1469 debug_elog2(DEBUG2, "CacheGet: not found :-(");
1470 return InvalidMultiXactId;
1471}
static int mxactMemberComparator(const void *arg1, const void *arg2)
Definition multixact.c:1409
#define qsort(a, b, c, d)
Definition port.h:495

References dlist_iter::cur, dclist_container, dclist_foreach, dclist_move_head(), DEBUG2, debug_elog2, debug_elog3, fb(), InvalidMultiXactId, mXactCacheEnt::members, mXactCacheEnt::multi, MXactCache, mxactMemberComparator(), mxid_to_string(), mXactCacheEnt::nmembers, and qsort.

Referenced by MultiXactIdCreateFromMembers().

◆ mXactCachePut()

static void mXactCachePut ( MultiXactId  multi,
int  nmembers,
MultiXactMember members 
)
static

Definition at line 1529 of file multixact.c.

1530{
1531 mXactCacheEnt *entry;
1532
1533 debug_elog3(DEBUG2, "CachePut: storing %s",
1534 mxid_to_string(multi, nmembers, members));
1535
1536 if (MXactContext == NULL)
1537 {
1538 /* The cache only lives as long as the current transaction */
1539 debug_elog2(DEBUG2, "CachePut: initializing memory context");
1541 "MultiXact cache context",
1543 }
1544
1545 entry = (mXactCacheEnt *)
1547 offsetof(mXactCacheEnt, members) +
1548 nmembers * sizeof(MultiXactMember));
1549
1550 entry->multi = multi;
1551 entry->nmembers = nmembers;
1552 memcpy(entry->members, members, nmembers * sizeof(MultiXactMember));
1553
1554 /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
1555 qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1556
1557 dclist_push_head(&MXactCache, &entry->node);
1559 {
1560 dlist_node *node;
1561
1564
1565 entry = dclist_container(mXactCacheEnt, node, node);
1566 debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
1567 entry->multi);
1568
1569 pfree(entry);
1570 }
1571}
static uint32 dclist_count(const dclist_head *head)
Definition ilist.h:932
static dlist_node * dclist_tail_node(dclist_head *head)
Definition ilist.h:920
static void dclist_delete_from(dclist_head *head, dlist_node *node)
Definition ilist.h:763
static void dclist_push_head(dclist_head *head, dlist_node *node)
Definition ilist.h:693
void * MemoryContextAlloc(MemoryContext context, Size size)
Definition mcxt.c:1232
MemoryContext TopTransactionContext
Definition mcxt.c:171
#define AllocSetContextCreate
Definition memutils.h:129
#define ALLOCSET_SMALL_SIZES
Definition memutils.h:170
#define MAX_CACHE_ENTRIES
Definition multixact.c:299
dlist_node node
Definition multixact.c:295

References ALLOCSET_SMALL_SIZES, AllocSetContextCreate, dclist_container, dclist_count(), dclist_delete_from(), dclist_push_head(), dclist_tail_node(), DEBUG2, debug_elog2, debug_elog3, fb(), MAX_CACHE_ENTRIES, mXactCacheEnt::members, memcpy(), MemoryContextAlloc(), mXactCacheEnt::multi, MXactCache, MXactContext, mxactMemberComparator(), mxid_to_string(), mXactCacheEnt::nmembers, mXactCacheEnt::node, pfree(), qsort, and TopTransactionContext.

Referenced by GetMultiXactIdMembers(), and MultiXactIdCreateFromMembers().

◆ mxactMemberComparator()

static int mxactMemberComparator ( const void arg1,
const void arg2 
)
static

Definition at line 1409 of file multixact.c.

1410{
1413
1414 if (member1.xid > member2.xid)
1415 return 1;
1416 if (member1.xid < member2.xid)
1417 return -1;
1418 if (member1.status > member2.status)
1419 return 1;
1420 if (member1.status < member2.status)
1421 return -1;
1422 return 0;
1423}

References fb().

Referenced by mXactCacheGetBySet(), and mXactCachePut().

◆ mxid_to_string()

char * mxid_to_string ( MultiXactId  multi,
int  nmembers,
MultiXactMember members 
)

Definition at line 1597 of file multixact.c.

1598{
1599 static char *str = NULL;
1601 int i;
1602
1603 if (str != NULL)
1604 pfree(str);
1605
1607
1608 appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1609 mxstatus_to_string(members[0].status));
1610
1611 for (i = 1; i < nmembers; i++)
1612 appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1613 mxstatus_to_string(members[i].status));
1614
1617 pfree(buf.data);
1618 return str;
1619}
const char * str
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition mcxt.c:1768
MemoryContext TopMemoryContext
Definition mcxt.c:166
static char buf[DEFAULT_XLOG_SEG_SIZE]
void appendStringInfo(StringInfo str, const char *fmt,...)
Definition stringinfo.c:145
void appendStringInfoChar(StringInfo str, char ch)
Definition stringinfo.c:242
void initStringInfo(StringInfo str)
Definition stringinfo.c:97

References appendStringInfo(), appendStringInfoChar(), buf, fb(), i, initStringInfo(), MemoryContextStrdup(), mxstatus_to_string(), pfree(), str, and TopMemoryContext.

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

◆ mxstatus_to_string()

char * mxstatus_to_string ( MultiXactStatus  status)

Definition at line 1574 of file multixact.c.

1575{
1576 switch (status)
1577 {
1579 return "keysh";
1581 return "sh";
1583 return "fornokeyupd";
1585 return "forupd";
1587 return "nokeyupd";
1589 return "upd";
1590 default:
1591 elog(ERROR, "unrecognized multixact status %d", status);
1592 return "";
1593 }
1594}
@ MultiXactStatusForShare
Definition multixact.h:39
@ MultiXactStatusForNoKeyUpdate
Definition multixact.h:40
@ MultiXactStatusNoKeyUpdate
Definition multixact.h:43
@ MultiXactStatusUpdate
Definition multixact.h:45
@ MultiXactStatusForUpdate
Definition multixact.h:41
@ MultiXactStatusForKeyShare
Definition multixact.h:38

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

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

◆ MyOldestMemberMXactIdSlot()

static MultiXactId * MyOldestMemberMXactIdSlot ( void  )
inlinestatic

Definition at line 240 of file multixact.c.

241{
242 /*
243 * The first MaxBackends entries in the OldestMemberMXactId array are
244 * reserved for regular backends. MyProcNumber should index into one of
245 * them.
246 */
249}
int MaxBackends
Definition globals.c:149

References Assert, MaxBackends, MyProcNumber, and OldestMemberMXactId.

Referenced by AtEOXact_MultiXact(), AtPrepare_MultiXact(), MultiXactIdCreate(), MultiXactIdExpand(), MultiXactIdSetOldestMember(), and PostPrepare_MultiXact().

◆ MyOldestVisibleMXactIdSlot()

static MultiXactId * MyOldestVisibleMXactIdSlot ( void  )
inlinestatic

◆ NextMultiXactId()

static MultiXactId NextMultiXactId ( MultiXactId  multi)
inlinestatic

Definition at line 103 of file multixact.c.

104{
105 return multi == MaxMultiXactId ? FirstMultiXactId : multi + 1;
106}

References FirstMultiXactId, and MaxMultiXactId.

Referenced by GetMultiXactIdMembers(), GetNewMultiXactId(), multixact_redo(), and RecordNewMultiXact().

◆ PerformMembersTruncation()

static void PerformMembersTruncation ( MultiXactOffset  newOldestOffset)
static

Definition at line 2643 of file multixact.c.

2644{
2647}
void SimpleLruTruncate(SlruDesc *ctl, int64 cutoffPage)
Definition slru.c:1458

References fb(), MultiXactMemberCtl, MXOffsetToMemberPage(), and SimpleLruTruncate().

Referenced by multixact_redo(), and TruncateMultiXact().

◆ PerformOffsetsTruncation()

static void PerformOffsetsTruncation ( MultiXactId  newOldestMulti)
static

Definition at line 2653 of file multixact.c.

2654{
2655 /*
2656 * We step back one multixact to avoid passing a cutoff page that hasn't
2657 * been created yet in the rare case that oldestMulti would be the first
2658 * item on a page and oldestMulti == nextMulti. In that case, if we
2659 * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
2660 * detection.
2661 */
2664}
static MultiXactId PreviousMultiXactId(MultiXactId multi)
Definition multixact.c:109

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

Referenced by multixact_redo(), and TruncateMultiXact().

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( FullTransactionId  fxid)

Definition at line 1670 of file multixact.c.

1671{
1673
1674 /*
1675 * Transfer our OldestMemberMXactId value to the slot reserved for the
1676 * prepared transaction.
1677 */
1680 {
1682
1683 /*
1684 * Even though storing MultiXactId is atomic, acquire lock to make
1685 * sure others see both changes, not just the reset of the slot of the
1686 * current backend. Using a volatile pointer might suffice, but this
1687 * isn't a hot spot.
1688 */
1690
1693
1695 }
1696
1697 /*
1698 * We don't need to transfer OldestVisibleMXactId value, because the
1699 * transaction is not going to be looking at any more multixacts once it's
1700 * prepared.
1701 *
1702 * We assume that storing a MultiXactId is atomic and so we need not take
1703 * MultiXactGenLock to do this.
1704 */
1706
1707 /*
1708 * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1709 */
1712}

References dclist_init(), fb(), InvalidMultiXactId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MXactCache, MXactContext, MyOldestMemberMXactIdSlot(), MyOldestVisibleMXactIdSlot(), PreparedXactOldestMemberMXactIdSlot(), and TwoPhaseGetDummyProcNumber().

Referenced by PrepareTransaction().

◆ PreparedXactOldestMemberMXactIdSlot()

static MultiXactId * PreparedXactOldestMemberMXactIdSlot ( ProcNumber  procno)
inlinestatic

Definition at line 252 of file multixact.c.

253{
255
258
259 /*
260 * The first MaxBackends entries in the OldestMemberMXactId array are
261 * reserved for regular backends. Prepared xacts come after them.
262 */
265}
#define FIRST_PREPARED_XACT_PROC_NUMBER
Definition proc.h:529

References Assert, fb(), FIRST_PREPARED_XACT_PROC_NUMBER, MaxBackends, NumMemberSlots, and OldestMemberMXactId.

Referenced by multixact_twophase_postcommit(), multixact_twophase_recover(), and PostPrepare_MultiXact().

◆ PreviousMultiXactId()

static MultiXactId PreviousMultiXactId ( MultiXactId  multi)
inlinestatic

Definition at line 109 of file multixact.c.

110{
111 return multi == FirstMultiXactId ? MaxMultiXactId : multi - 1;
112}

References FirstMultiXactId, and MaxMultiXactId.

Referenced by PerformOffsetsTruncation().

◆ ReadMultiXactIdRange()

◆ ReadNextMultiXactId()

◆ RecordNewMultiXact()

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

Definition at line 816 of file multixact.c.

818{
819 int64 pageno;
821 int entryno;
822 int slotno;
826 int next_entryno;
828 MultiXactOffset next_offset;
829 LWLock *lock;
831
832 /* position of this multixid in the offsets SLRU area */
833 pageno = MultiXactIdToOffsetPage(multi);
835
836 /* position of the next multixid */
837 next = NextMultiXactId(multi);
840
841 /*
842 * Set the starting offset of this multixid's members.
843 *
844 * In the common case, it was already set by the previous
845 * RecordNewMultiXact call, as this was the next multixid of the previous
846 * multixid. But if multiple backends are generating multixids
847 * concurrently, we might race ahead and get called before the previous
848 * multixid.
849 */
852
853 slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, &multi);
854 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
855 offptr += entryno;
856
857 if (*offptr != offset)
858 {
859 /* should already be set to the correct value, or not at all */
860 Assert(*offptr == 0);
861 *offptr = offset;
862 MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
863 }
864
865 /*
866 * Set the next multixid's offset to the end of this multixid's members.
867 */
868 if (next_pageno == pageno)
869 {
870 next_offptr = offptr + 1;
871 }
872 else
873 {
874 /* must be the first entry on the page */
876
877 /* Swap the lock for a lock on the next page */
878 LWLockRelease(lock);
881
883 next_offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
885 }
886
887 /* Like in GetNewMultiXactId(), skip over offset 0 */
888 next_offset = offset + nmembers;
889 if (next_offset == 0)
890 next_offset = 1;
891 if (*next_offptr != next_offset)
892 {
893 /* should already be set to the correct value, or not at all */
894 Assert(*next_offptr == 0);
895 *next_offptr = next_offset;
896 MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
897 }
898
899 /* Release MultiXactOffset SLRU lock. */
900 LWLockRelease(lock);
901
902 prev_pageno = -1;
903
904 for (int i = 0; i < nmembers; i++, offset++)
905 {
909 int bshift;
910 int flagsoff;
911 int memberoff;
912
913 Assert(members[i].status <= MultiXactStatusUpdate);
914
915 pageno = MXOffsetToMemberPage(offset);
919
920 if (pageno != prev_pageno)
921 {
923
924 /*
925 * MultiXactMember SLRU page is changed so check if this new page
926 * fall into the different SLRU bank then release the old bank's
927 * lock and acquire lock on the new bank.
928 */
930 if (lock != prevlock)
931 {
932 if (prevlock != NULL)
934
936 prevlock = lock;
937 }
940 prev_pageno = pageno;
941 }
942
944 (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
945
946 *memberptr = members[i].xid;
947
948 flagsptr = (uint32 *)
949 (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
950
952 flagsval &= ~(((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) << bshift);
953 flagsval |= (members[i].status << bshift);
955
956 MultiXactMemberCtl->shared->page_dirty[slotno] = true;
957 }
958
959 if (prevlock != NULL)
961}
#define MXACT_MEMBER_BITS_PER_XACT

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

Referenced by multixact_redo(), and MultiXactIdCreateFromMembers().

◆ SetMultiXactIdLimit()

void SetMultiXactIdLimit ( MultiXactId  oldest_datminmxid,
Oid  oldest_datoid 
)

Definition at line 2085 of file multixact.c.

2086{
2087 MultiXactId multiVacLimit;
2088 MultiXactId multiWarnLimit;
2089 MultiXactId multiStopLimit;
2090 MultiXactId multiWrapLimit;
2092
2094
2095 /*
2096 * We pretend that a wrap will happen halfway through the multixact ID
2097 * space, but that's not really true, because multixacts wrap differently
2098 * from transaction IDs.
2099 */
2100 multiWrapLimit = oldest_datminmxid + (MaxMultiXactId >> 1);
2101 if (multiWrapLimit < FirstMultiXactId)
2102 multiWrapLimit += FirstMultiXactId;
2103
2104 /*
2105 * We'll refuse to continue assigning MultiXactIds once we get within 3M
2106 * multi of data loss. See SetTransactionIdLimit.
2107 */
2108 multiStopLimit = multiWrapLimit - 3000000;
2109 if (multiStopLimit < FirstMultiXactId)
2110 multiStopLimit -= FirstMultiXactId;
2111
2112 /*
2113 * We'll start complaining loudly when we get within 100M multis of data
2114 * loss. This is kind of arbitrary, but if you let your gas gauge get
2115 * down to 5% of full, would you be looking for the next gas station? We
2116 * need to be fairly liberal about this number because there are lots of
2117 * scenarios where most transactions are done by automatic clients that
2118 * won't pay attention to warnings. (No, we're not gonna make this
2119 * configurable. If you know enough to configure it, you know enough to
2120 * not get in this kind of trouble in the first place.)
2121 */
2122 multiWarnLimit = multiWrapLimit - 100000000;
2123 if (multiWarnLimit < FirstMultiXactId)
2124 multiWarnLimit -= FirstMultiXactId;
2125
2126 /*
2127 * We'll start trying to force autovacuums when oldest_datminmxid gets to
2128 * be more than autovacuum_multixact_freeze_max_age mxids old.
2129 *
2130 * Note: autovacuum_multixact_freeze_max_age is a PGC_POSTMASTER parameter
2131 * so that we don't have to worry about dealing with on-the-fly changes in
2132 * its value. See SetTransactionIdLimit.
2133 */
2135 if (multiVacLimit < FirstMultiXactId)
2136 multiVacLimit += FirstMultiXactId;
2137
2138 /* Grab lock for just long enough to set the new limit values */
2142 MultiXactState->multiVacLimit = multiVacLimit;
2143 MultiXactState->multiWarnLimit = multiWarnLimit;
2144 MultiXactState->multiStopLimit = multiStopLimit;
2145 MultiXactState->multiWrapLimit = multiWrapLimit;
2148
2149 /* Log the info */
2151 (errmsg_internal("MultiXactId wrap limit is %u, limited by database with OID %u",
2152 multiWrapLimit, oldest_datoid)));
2153
2154 /*
2155 * Computing the actual limits is only possible once the data directory is
2156 * in a consistent state. There's no need to compute the limits while
2157 * still replaying WAL - no decisions about new multis are made even
2158 * though multixact creations might be replayed. So we'll only do further
2159 * checks after TrimMultiXact() has been called.
2160 */
2162 return;
2163
2165
2166 /*
2167 * Offsets are 64-bits wide and never wrap around, so we don't need to
2168 * consider them for emergency autovacuum purposes. But now that we're in
2169 * a consistent state, determine MultiXactState->oldestOffset. It will be
2170 * used to adjust the freezing cutoff, to keep the offsets disk usage in
2171 * check.
2172 */
2174
2175 /*
2176 * If past the autovacuum force point, immediately signal an autovac
2177 * request. The reason for this is that autovac only processes one
2178 * database per invocation. Once it's finished cleaning up the oldest
2179 * database, it'll call here, and we'll signal the postmaster to start
2180 * another iteration immediately if there are still any old databases.
2181 */
2182 if (MultiXactIdPrecedes(multiVacLimit, curMulti) && IsUnderPostmaster)
2184
2185 /* Give an immediate warning if past the wrap warn point */
2186 if (MultiXactIdPrecedes(multiWarnLimit, curMulti))
2187 {
2188 char *oldest_datname;
2189
2190 /*
2191 * We can be called when not inside a transaction, for example during
2192 * StartupXLOG(). In such a case we cannot do database access, so we
2193 * must just report the oldest DB's OID.
2194 *
2195 * Note: it's also possible that get_database_name fails and returns
2196 * NULL, for example because the database just got dropped. We'll
2197 * still warn, even though the warning might now be unnecessary.
2198 */
2199 if (IsTransactionState())
2201 else
2203
2204 if (oldest_datname)
2206 (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
2207 "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
2208 multiWrapLimit - curMulti,
2210 multiWrapLimit - curMulti),
2211 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
2212 (double) (multiWrapLimit - curMulti) / (MaxMultiXactId / 2) * 100),
2213 errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2214 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2215 else
2217 (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
2218 "database with OID %u must be vacuumed before %u more MultiXactIds are used",
2219 multiWrapLimit - curMulti,
2221 multiWrapLimit - curMulti),
2222 errdetail("Approximately %.2f%% of MultiXactIds are available for use.",
2223 (double) (multiWrapLimit - curMulti) / (MaxMultiXactId / 2) * 100),
2224 errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2225 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2226 }
2227}
int int errmsg_internal(const char *fmt,...) pg_attribute_printf(1
static void SetOldestOffset(void)
Definition multixact.c:2417
bool IsTransactionState(void)
Definition xact.c:389

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

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

◆ SetOldestOffset()

static void SetOldestOffset ( void  )
static

Definition at line 2417 of file multixact.c.

2418{
2419 MultiXactId oldestMultiXactId;
2420 MultiXactId nextMXact;
2421 MultiXactOffset oldestOffset = 0; /* placate compiler */
2422 MultiXactOffset nextOffset;
2423 bool oldestOffsetKnown = false;
2424
2425 /*
2426 * NB: Have to prevent concurrent truncation, we might otherwise try to
2427 * lookup an oldestMulti that's concurrently getting truncated away.
2428 */
2430
2431 /* Read relevant fields from shared memory. */
2433 oldestMultiXactId = MultiXactState->oldestMultiXactId;
2434 nextMXact = MultiXactState->nextMXact;
2435 nextOffset = MultiXactState->nextOffset;
2438
2439 /*
2440 * Determine the offset of the oldest multixact. Normally, we can read
2441 * the offset from the multixact itself, but there's an important special
2442 * case: if there are no multixacts in existence at all, oldestMXact
2443 * obviously can't point to one. It will instead point to the multixact
2444 * ID that will be assigned the next time one is needed.
2445 */
2446 if (oldestMultiXactId == nextMXact)
2447 {
2448 /*
2449 * When the next multixact gets created, it will be stored at the next
2450 * offset.
2451 */
2452 oldestOffset = nextOffset;
2453 oldestOffsetKnown = true;
2454 }
2455 else
2456 {
2457 /*
2458 * Look up the offset at which the oldest existing multixact's members
2459 * are stored. If we cannot find it, be careful not to fail, and
2460 * leave oldestOffset unchanged. oldestOffset is initialized to zero
2461 * at system startup, which prevents truncating members until a proper
2462 * value is calculated.
2463 *
2464 * (We had bugs in early releases of PostgreSQL 9.3.X and 9.4.X where
2465 * the supposedly-earliest multixact might not really exist. Those
2466 * should be long gone by now, so this should not fail, but let's
2467 * still be defensive.)
2468 */
2470 find_multixact_start(oldestMultiXactId, &oldestOffset);
2471
2474 (errmsg_internal("oldest MultiXactId member is at offset %" PRIu64,
2475 oldestOffset)));
2476 else
2477 ereport(LOG,
2478 (errmsg("MultiXact member truncation is disabled because oldest checkpointed MultiXact %u does not exist on disk",
2479 oldestMultiXactId)));
2480 }
2481
2483
2484 /* Install the computed value */
2486 {
2488 MultiXactState->oldestOffset = oldestOffset;
2490 }
2491}
#define LOG
Definition elog.h:32
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result)
Definition multixact.c:2503

References Assert, DEBUG1, ereport, errmsg, errmsg_internal(), fb(), find_multixact_start(), MultiXactStateData::finishedStartup, LOG, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactState, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactId, and MultiXactStateData::oldestOffset.

Referenced by SetMultiXactIdLimit().

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 1879 of file multixact.c.

1880{
1883 int64 pageno;
1884
1885 /*
1886 * Initialize offset's idea of the latest page number.
1887 */
1888 pageno = MultiXactIdToOffsetPage(multi);
1889 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
1890 pageno);
1891
1892 /*
1893 * Initialize member's idea of the latest page number.
1894 */
1895 pageno = MXOffsetToMemberPage(offset);
1896 pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
1897 pageno);
1898}
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition atomics.h:485

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

Referenced by StartupXLOG().

◆ TrimMultiXact()

void TrimMultiXact ( void  )

Definition at line 1904 of file multixact.c.

1905{
1906 MultiXactId nextMXact;
1907 MultiXactOffset offset;
1910 int64 pageno;
1911 int entryno;
1912 int flagsoff;
1913
1915 nextMXact = MultiXactState->nextMXact;
1916 offset = MultiXactState->nextOffset;
1920
1921 /* Clean up offsets state */
1922
1923 /*
1924 * (Re-)Initialize our idea of the latest page number for offsets.
1925 */
1926 pageno = MultiXactIdToOffsetPage(nextMXact);
1927 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
1928 pageno);
1929
1930 /*
1931 * Set the offset of nextMXact on the offsets page. This is normally done
1932 * in RecordNewMultiXact() of the previous multixact, but let's be sure
1933 * the next page exists, if the nextMXact was reset with pg_resetwal for
1934 * example.
1935 *
1936 * Zero out the remainder of the page. See notes in TrimCLOG() for
1937 * background. Unlike CLOG, some WAL record covers every pg_multixact
1938 * SLRU mutation. Since, also unlike CLOG, we ignore the WAL rule "write
1939 * xlog before data," nextMXact successors may carry obsolete, nonzero
1940 * offset values.
1941 */
1942 entryno = MultiXactIdToOffsetEntry(nextMXact);
1943 {
1944 int slotno;
1947
1949 if (entryno == 0 || nextMXact == FirstMultiXactId)
1951 else
1952 slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, &nextMXact);
1953 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1954 offptr += entryno;
1955
1956 *offptr = offset;
1957 if (entryno != 0 && (entryno + 1) * sizeof(MultiXactOffset) != BLCKSZ)
1958 MemSet(offptr + 1, 0, BLCKSZ - (entryno + 1) * sizeof(MultiXactOffset));
1959
1960 MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
1961 LWLockRelease(lock);
1962 }
1963
1964 /*
1965 * And the same for members.
1966 *
1967 * (Re-)Initialize our idea of the latest page number for members.
1968 */
1969 pageno = MXOffsetToMemberPage(offset);
1970 pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
1971 pageno);
1972
1973 /*
1974 * Zero out the remainder of the current members page. See notes in
1975 * TrimCLOG() for motivation.
1976 */
1978 if (flagsoff != 0)
1979 {
1981 int slotno;
1983 int memberoff;
1985
1989 xidptr = (TransactionId *)
1990 (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
1991
1993
1994 /*
1995 * Note: we don't need to zero out the flag bits in the remaining
1996 * members of the current group, because they are always reset before
1997 * writing.
1998 */
1999
2000 MultiXactMemberCtl->shared->page_dirty[slotno] = true;
2001 LWLockRelease(lock);
2002 }
2003
2004 /* signal that we're officially up */
2008
2009 /* Now compute how far away the next multixid wraparound is. */
2011}
#define MemSet(start, val, len)
Definition c.h:1107

References fb(), MultiXactStateData::finishedStartup, FirstMultiXactId, InvalidMultiXactId, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MemSet, MultiXactIdToOffsetEntry(), MultiXactIdToOffsetPage(), MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactState, MXOffsetToFlagsOffset(), MXOffsetToMemberOffset(), MXOffsetToMemberPage(), MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestMultiXactId, pg_atomic_write_u64(), SetMultiXactIdLimit(), SimpleLruGetBankLock(), SimpleLruReadPage(), and SimpleLruZeroPage().

Referenced by StartupXLOG().

◆ TruncateMultiXact()

void TruncateMultiXact ( MultiXactId  newOldestMulti,
Oid  newOldestMultiDB 
)

Definition at line 2678 of file multixact.c.

2679{
2680 MultiXactId oldestMulti;
2681 MultiXactId nextMulti;
2683 MultiXactOffset nextOffset;
2684
2688
2689 /*
2690 * We can only allow one truncation to happen at once. Otherwise parts of
2691 * members might vanish while we're doing lookups or similar. There's no
2692 * need to have an interlock with creating new multis or such, since those
2693 * are constrained by the limits (which only grow, never shrink).
2694 */
2696
2698 nextMulti = MultiXactState->nextMXact;
2699 nextOffset = MultiXactState->nextOffset;
2700 oldestMulti = MultiXactState->oldestMultiXactId;
2702
2703 /*
2704 * Make sure to only attempt truncation if there's values to truncate
2705 * away. In normal processing values shouldn't go backwards, but there's
2706 * some corner cases (due to bugs) where that's possible.
2707 */
2709 {
2711 return;
2712 }
2713
2714 /*
2715 * Compute up to where to truncate MultiXactMember. Lookup the
2716 * corresponding member offset for newOldestMulti for that.
2717 */
2718 if (newOldestMulti == nextMulti)
2719 {
2720 /* there are NO MultiXacts */
2721 newOldestOffset = nextOffset;
2722 }
2724 {
2725 ereport(LOG,
2726 (errmsg("cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
2727 newOldestMulti)));
2729 return;
2730 }
2731
2732 /*
2733 * On crash, MultiXactIdCreateFromMembers() can leave behind multixids
2734 * that were not yet written out and hence have zero offset on disk. If
2735 * such a multixid becomes oldestMulti, we won't be able to look up its
2736 * offset. That should be rare, so we don't try to do anything smart about
2737 * it. Just skip the truncation, and hope that by the next truncation
2738 * attempt, oldestMulti has advanced to a valid multixid.
2739 */
2740 if (newOldestOffset == 0)
2741 {
2742 ereport(LOG,
2743 (errmsg("cannot truncate up to MultiXact %u because it has invalid offset, skipping truncation",
2744 newOldestMulti)));
2746 return;
2747 }
2748
2749 elog(DEBUG1, "performing multixact truncation: "
2750 "oldestMulti %u (offsets segment %" PRIx64 "), "
2751 "oldestOffset %" PRIu64 " (members segment %" PRIx64 ")",
2756
2757 /*
2758 * Do truncation, and the WAL logging of the truncation, in a critical
2759 * section. That way offsets/members cannot get out of sync anymore, i.e.
2760 * once consistent the newOldestMulti will always exist in members, even
2761 * if we crashed in the wrong moment.
2762 */
2764
2765 /*
2766 * Prevent checkpoints from being scheduled concurrently. This is critical
2767 * because otherwise a truncation record might not be replayed after a
2768 * crash/basebackup, even though the state of the data directory would
2769 * require it.
2770 */
2773
2774 /* WAL log truncation */
2776
2777 /*
2778 * Update in-memory limits before performing the truncation, while inside
2779 * the critical section: Have to do it before truncation, to prevent
2780 * concurrent lookups of those values. Has to be inside the critical
2781 * section as otherwise a future call to this function would error out,
2782 * while looking up the oldest member in offsets, if our caller crashes
2783 * before updating the limits.
2784 */
2790
2791 /* First truncate members */
2793
2794 /* Then offsets */
2796
2798
2801}
static void WriteMTruncateXlogRec(Oid oldestMultiDB, MultiXactId endTruncOff, MultiXactOffset endTruncMemb)
Definition multixact.c:2894
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
Definition multixact.c:2879
#define DELAY_CHKPT_START
Definition proc.h:139
PGPROC * MyProc
Definition proc.c:71
int delayChkptFlags
Definition proc.h:260

References Assert, DEBUG1, DELAY_CHKPT_START, PGPROC::delayChkptFlags, elog, END_CRIT_SECTION, ereport, errmsg, fb(), find_multixact_start(), MultiXactStateData::finishedStartup, LOG, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MultiXactIdPrecedesOrEquals(), MultiXactIdToOffsetSegment(), MultiXactState, MXOffsetToMemberSegment(), MyProc, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestMultiXactId, MultiXactStateData::oldestOffset, PerformMembersTruncation(), PerformOffsetsTruncation(), RecoveryInProgress(), START_CRIT_SECTION, and WriteMTruncateXlogRec().

Referenced by vac_truncate_clog().

◆ WriteMTruncateXlogRec()

static void WriteMTruncateXlogRec ( Oid  oldestMultiDB,
MultiXactId  endTruncOff,
MultiXactOffset  endTruncMemb 
)
static

Definition at line 2894 of file multixact.c.

2897{
2900
2901 xlrec.oldestMultiDB = oldestMultiDB;
2902 xlrec.oldestMulti = oldestMulti;
2903 xlrec.oldestOffset = oldestOffset;
2904
2909}
void XLogFlush(XLogRecPtr record)
Definition xlog.c:2801
uint64 XLogRecPtr
Definition xlogdefs.h:21

References fb(), xl_multixact_truncate::oldestMultiDB, SizeOfMultiXactTruncate, XLOG_MULTIXACT_TRUNCATE_ID, XLogBeginInsert(), XLogFlush(), XLogInsert(), and XLogRegisterData().

Referenced by TruncateMultiXact().

Variable Documentation

◆ MultiXactMemberSlruDesc

SlruDesc MultiXactMemberSlruDesc
static

Definition at line 123 of file multixact.c.

Referenced by MultiXactShmemRequest().

◆ MultiXactOffsetSlruDesc

SlruDesc MultiXactOffsetSlruDesc
static

Definition at line 122 of file multixact.c.

Referenced by MultiXactShmemRequest().

◆ MultiXactShmemCallbacks

const ShmemCallbacks MultiXactShmemCallbacks
Initial value:
= {
.request_fn = MultiXactShmemRequest,
.init_fn = MultiXactShmemInit,
.attach_fn = MultiXactShmemAttach,
}
static void MultiXactShmemInit(void *arg)
Definition multixact.c:1817
static void MultiXactShmemRequest(void *arg)
Definition multixact.c:1766
static void MultiXactShmemAttach(void *arg)
Definition multixact.c:1832

Definition at line 233 of file multixact.c.

233 {
234 .request_fn = MultiXactShmemRequest,
235 .init_fn = MultiXactShmemInit,
236 .attach_fn = MultiXactShmemAttach,
237};

◆ MultiXactState

◆ MXactCache

◆ MXactContext

MemoryContext MXactContext = NULL
static

Definition at line 301 of file multixact.c.

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

◆ OldestMemberMXactId

◆ OldestVisibleMXactId

MultiXactId* OldestVisibleMXactId
static