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 "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
 

Macros

#define MULTIXACT_MEMBER_LOW_THRESHOLD   UINT64CONST(2000000000)
 
#define MULTIXACT_MEMBER_HIGH_THRESHOLD   UINT64CONST(4000000000)
 
#define MultiXactOffsetCtl   (&MultiXactOffsetCtlData)
 
#define MultiXactMemberCtl   (&MultiXactMemberCtlData)
 
#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)
 
#define MAX_CACHE_ENTRIES   256
 
#define debug_elog2(a, b)
 
#define debug_elog3(a, b, c)
 
#define debug_elog4(a, b, c, d)
 
#define debug_elog5(a, b, c, d, e)
 
#define debug_elog6(a, b, c, d, e, f)
 
#define SHARED_MULTIXACT_STATE_SIZE
 

Typedefs

typedef struct MultiXactStateData MultiXactStateData
 
typedef struct mXactCacheEnt mXactCacheEnt
 

Functions

static MultiXactId NextMultiXactId (MultiXactId multi)
 
static MultiXactId PreviousMultiXactId (MultiXactId multi)
 
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 bool MultiXactOffsetPagePrecedes (int64 page1, int64 page2)
 
static bool MultiXactMemberPagePrecedes (int64 page1, int64 page2)
 
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)
 
Size MultiXactShmemSize (void)
 
void MultiXactShmemInit (void)
 
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 SlruCtlData MultiXactOffsetCtlData
 
static SlruCtlData MultiXactMemberCtlData
 
static MultiXactStateDataMultiXactState
 
static MultiXactIdOldestMemberMXactId
 
static MultiXactIdOldestVisibleMXactId
 
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 257 of file multixact.c.

◆ debug_elog3

#define debug_elog3 (   a,
  b,
  c 
)

Definition at line 258 of file multixact.c.

◆ debug_elog4

#define debug_elog4 (   a,
  b,
  c,
 
)

Definition at line 259 of file multixact.c.

◆ debug_elog5

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

Definition at line 260 of file multixact.c.

◆ debug_elog6

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

Definition at line 261 of file multixact.c.

◆ MAX_CACHE_ENTRIES

#define MAX_CACHE_ENTRIES   256

Definition at line 246 of file multixact.c.

◆ MaxOldestSlot

#define MaxOldestSlot   (MaxBackends + max_prepared_xacts)

Definition at line 213 of file multixact.c.

◆ MULTIXACT_MEMBER_HIGH_THRESHOLD

#define MULTIXACT_MEMBER_HIGH_THRESHOLD   UINT64CONST(4000000000)

Definition at line 99 of file multixact.c.

◆ MULTIXACT_MEMBER_LOW_THRESHOLD

#define MULTIXACT_MEMBER_LOW_THRESHOLD   UINT64CONST(2000000000)

Definition at line 98 of file multixact.c.

◆ MultiXactMemberCtl

#define MultiXactMemberCtl   (&MultiXactMemberCtlData)

Definition at line 120 of file multixact.c.

◆ MultiXactOffsetCtl

#define MultiXactOffsetCtl   (&MultiXactOffsetCtlData)

Definition at line 119 of file multixact.c.

◆ SHARED_MULTIXACT_STATE_SIZE

#define SHARED_MULTIXACT_STATE_SIZE
Value:
add_size(offsetof(MultiXactStateData, perBackendXactIds), \
TransactionId MultiXactId
Definition c.h:686
#define MaxOldestSlot
Definition multixact.c:213
static int fb(int x)
Size add_size(Size s1, Size s2)
Definition shmem.c:495
Size mul_size(Size s1, Size s2)
Definition shmem.c:510

Typedef Documentation

◆ MultiXactStateData

◆ mXactCacheEnt

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1568 of file multixact.c.

1569{
1570 /*
1571 * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1572 * which should only be valid while within a transaction.
1573 *
1574 * We assume that storing a MultiXactId is atomic and so we need not take
1575 * MultiXactGenLock to do this.
1576 */
1579
1580 /*
1581 * Discard the local MultiXactId cache. Since MXactContext was created as
1582 * a child of TopTransactionContext, we needn't delete it explicitly.
1583 */
1586}
ProcNumber MyProcNumber
Definition globals.c:90
static void dclist_init(dclist_head *head)
Definition ilist.h:671
static MemoryContext MXactContext
Definition multixact.c:248
static MultiXactId * OldestVisibleMXactId
Definition multixact.c:218
static dclist_head MXactCache
Definition multixact.c:247
static MultiXactId * OldestMemberMXactId
Definition multixact.c:217
#define InvalidMultiXactId
Definition multixact.h:25

References dclist_init(), fb(), InvalidMultiXactId, MXactCache, MXactContext, MyProcNumber, OldestMemberMXactId, and OldestVisibleMXactId.

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

◆ AtPrepare_MultiXact()

void AtPrepare_MultiXact ( void  )

Definition at line 1596 of file multixact.c.

1597{
1599
1602 &myOldestMember, sizeof(MultiXactId));
1603}
#define MultiXactIdIsValid(multi)
Definition multixact.h:29
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
Definition twophase.c:1271
#define TWOPHASE_RM_MULTIXACT_ID

References fb(), MultiXactIdIsValid, MyProcNumber, OldestMemberMXactId, RegisterTwoPhaseRecord(), and TWOPHASE_RM_MULTIXACT_ID.

Referenced by PrepareTransaction().

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 1793 of file multixact.c.

1794{
1795 /* Zero the initial pages and flush them to disk */
1798}
#define MultiXactMemberCtl
Definition multixact.c:120
#define MultiXactOffsetCtl
Definition multixact.c:119
void SimpleLruZeroAndWritePage(SlruCtl ctl, int64 pageno)
Definition slru.c:444

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 1782 of file multixact.c.

1783{
1784 return check_slru_buffers("multixact_member_buffers", newval);
1785}
#define newval
bool check_slru_buffers(const char *name, int *newval)
Definition slru.c:355

References check_slru_buffers(), and newval.

◆ check_multixact_offset_buffers()

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

Definition at line 1773 of file multixact.c.

1774{
1775 return check_slru_buffers("multixact_offset_buffers", newval);
1776}

References check_slru_buffers(), and newval.

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 1968 of file multixact.c.

1969{
1971
1972 /*
1973 * Write dirty MultiXact pages to disk. This may result in sync requests
1974 * queued for later handling by ProcessSyncRequests(), as part of the
1975 * checkpoint.
1976 */
1979
1981}
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition slru.c:1347

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

Referenced by CheckPointGuts().

◆ ExtendMultiXactMember()

static void ExtendMultiXactMember ( MultiXactOffset  offset,
int  nmembers 
)
static

Definition at line 2242 of file multixact.c.

2243{
2244 /*
2245 * It's possible that the members span more than one page of the members
2246 * file, so we loop to ensure we consider each page. The coding is not
2247 * optimal if the members span several pages, but that seems unusual
2248 * enough to not worry much about.
2249 */
2250 while (nmembers > 0)
2251 {
2252 int flagsoff;
2253 int flagsbit;
2255
2256 /*
2257 * Only zero when at first entry of a page.
2258 */
2261 if (flagsoff == 0 && flagsbit == 0)
2262 {
2263 int64 pageno;
2264 LWLock *lock;
2265
2266 pageno = MXOffsetToMemberPage(offset);
2268
2270
2271 /* Zero the page and make a WAL entry about it */
2275
2276 LWLockRelease(lock);
2277 }
2278
2279 /* Compute the number of items till end of current page. */
2281
2282 /*
2283 * Advance to next page. OK if nmembers goes negative.
2284 */
2285 nmembers -= difference;
2286 offset += difference;
2287 }
2288}
int64_t int64
Definition c.h:553
uint32_t uint32
Definition c.h:556
Datum difference(PG_FUNCTION_ARGS)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition lwlock.c:1176
void LWLockRelease(LWLock *lock)
Definition lwlock.c:1793
@ LW_EXCLUSIVE
Definition lwlock.h:112
#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(SlruCtl ctl, int64 pageno)
Definition slru.c:375
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition slru.h:160
XLogRecPtr XLogSimpleInsertInt64(RmgrId rmid, uint8 info, int64 value)
Definition xloginsert.c:543

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 2208 of file multixact.c.

2209{
2210 int64 pageno;
2211 LWLock *lock;
2212
2213 /*
2214 * No work except at first MultiXactId of a page. But beware: just after
2215 * wraparound, the first MultiXactId of page zero is FirstMultiXactId.
2216 */
2217 if (MultiXactIdToOffsetEntry(multi) != 0 &&
2218 multi != FirstMultiXactId)
2219 return;
2220
2221 pageno = MultiXactIdToOffsetPage(multi);
2223
2225
2226 /* Zero the page and make a WAL entry about it */
2229 pageno);
2230
2231 LWLockRelease(lock);
2232}
#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 2424 of file multixact.c.

2425{
2426 MultiXactOffset offset;
2427 int64 pageno;
2428 int entryno;
2429 int slotno;
2431
2433
2434 pageno = MultiXactIdToOffsetPage(multi);
2436
2437 /*
2438 * Write out dirty data, so PhysicalPageExists can work correctly.
2439 */
2442
2444 return false;
2445
2446 /* lock is acquired by SimpleLruReadPage_ReadOnly */
2448 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
2449 offptr += entryno;
2450 offset = *offptr;
2452
2453 *result = offset;
2454 return true;
2455}
#define Assert(condition)
Definition c.h:883
uint64 MultiXactOffset
Definition c.h:688
static MultiXactStateData * MultiXactState
Definition multixact.c:216
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
Definition slru.c:630
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int64 pageno)
Definition slru.c:771

References Assert, fb(), MultiXactStateData::finishedStartup, LWLockRelease(), MultiXactIdToOffsetEntry(), MultiXactIdToOffsetPage(), MultiXactMemberCtl, MultiXactOffsetCtl, MultiXactState, 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 1113 of file multixact.c.

1115{
1116 int64 pageno;
1118 int entryno;
1119 int slotno;
1121 MultiXactOffset offset;
1123 int length;
1125 MultiXactId nextMXact;
1126 MultiXactMember *ptr;
1127 LWLock *lock;
1128
1129 debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
1130
1131 if (!MultiXactIdIsValid(multi) || from_pgupgrade)
1132 {
1133 *members = NULL;
1134 return -1;
1135 }
1136
1137 /* See if the MultiXactId is in the local cache */
1138 length = mXactCacheGetById(multi, members);
1139 if (length >= 0)
1140 {
1141 debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
1142 mxid_to_string(multi, length, *members));
1143 return length;
1144 }
1145
1146 /* Set our OldestVisibleMXactId[] entry if we didn't already */
1148
1149 /*
1150 * If we know the multi is used only for locking and not for updates, then
1151 * we can skip checking if the value is older than our oldest visible
1152 * multi. It cannot possibly still be running.
1153 */
1154 if (isLockOnly &&
1156 {
1157 debug_elog2(DEBUG2, "GetMembers: a locker-only multi is too old");
1158 *members = NULL;
1159 return -1;
1160 }
1161
1162 /*
1163 * We check known limits on MultiXact before resorting to the SLRU area.
1164 *
1165 * An ID older than MultiXactState->oldestMultiXactId cannot possibly be
1166 * useful; it has already been removed, or will be removed shortly, by
1167 * truncation. If one is passed, an error is raised.
1168 *
1169 * Also, an ID >= nextMXact shouldn't ever be seen here; if it is seen, it
1170 * implies undetected ID wraparound has occurred. This raises a hard
1171 * error.
1172 *
1173 * Shared lock is enough here since we aren't modifying any global state.
1174 * Acquire it just long enough to grab the current counter values.
1175 */
1177
1179 nextMXact = MultiXactState->nextMXact;
1180
1182
1183 if (MultiXactIdPrecedes(multi, oldestMXact))
1184 ereport(ERROR,
1186 errmsg("MultiXactId %u does no longer exist -- apparent wraparound",
1187 multi)));
1188
1189 if (!MultiXactIdPrecedes(multi, nextMXact))
1190 ereport(ERROR,
1192 errmsg("MultiXactId %u has not been created yet -- apparent wraparound",
1193 multi)));
1194
1195 /*
1196 * Find out the offset at which we need to start reading MultiXactMembers
1197 * and the number of members in the multixact. We determine the latter as
1198 * the difference between this multixact's starting offset and the next
1199 * one's.
1200 */
1201 pageno = MultiXactIdToOffsetPage(multi);
1203
1204 /* Acquire the bank lock for the page we need. */
1207
1208 /* read this multi's offset */
1209 slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
1210 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1211 offptr += entryno;
1212 offset = *offptr;
1213
1214 if (offset == 0)
1215 ereport(ERROR,
1217 errmsg("MultiXact %u has invalid offset", multi)));
1218
1219 /* read next multi's offset */
1220 {
1222
1223 /* handle wraparound if needed */
1224 tmpMXact = NextMultiXactId(multi);
1225
1226 prev_pageno = pageno;
1227
1230
1231 if (pageno != prev_pageno)
1232 {
1233 LWLock *newlock;
1234
1235 /*
1236 * Since we're going to access a different SLRU page, if this page
1237 * falls under a different bank, release the old bank's lock and
1238 * acquire the lock of the new bank.
1239 */
1241 if (newlock != lock)
1242 {
1243 LWLockRelease(lock);
1245 lock = newlock;
1246 }
1248 }
1249
1250 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1251 offptr += entryno;
1253 }
1254
1255 LWLockRelease(lock);
1256 lock = NULL;
1257
1258 /* Sanity check the next offset */
1259 if (nextMXOffset == 0)
1260 ereport(ERROR,
1262 errmsg("MultiXact %u has invalid next offset", multi)));
1263 if (nextMXOffset == offset)
1264 ereport(ERROR,
1266 errmsg("MultiXact %u with offset (%" PRIu64 ") has zero members",
1267 multi, offset)));
1268 if (nextMXOffset < offset)
1269 ereport(ERROR,
1271 errmsg("MultiXact %u has offset (%" PRIu64 ") greater than its next offset (%" PRIu64 ")",
1272 multi, offset, nextMXOffset)));
1273 if (nextMXOffset - offset > INT32_MAX)
1274 ereport(ERROR,
1276 errmsg("MultiXact %u has too many members (%" PRIu64 ")",
1277 multi, nextMXOffset - offset)));
1278 length = nextMXOffset - offset;
1279
1280 /* read the members */
1281 ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
1282 prev_pageno = -1;
1283 for (int i = 0; i < length; i++, offset++)
1284 {
1287 int flagsoff;
1288 int bshift;
1289 int memberoff;
1290
1291 pageno = MXOffsetToMemberPage(offset);
1293
1294 if (pageno != prev_pageno)
1295 {
1296 LWLock *newlock;
1297
1298 /*
1299 * Since we're going to access a different SLRU page, if this page
1300 * falls under a different bank, release the old bank's lock and
1301 * acquire the lock of the new bank.
1302 */
1304 if (newlock != lock)
1305 {
1306 if (lock)
1307 LWLockRelease(lock);
1309 lock = newlock;
1310 }
1311
1312 slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
1313 prev_pageno = pageno;
1314 }
1315
1317 (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
1319
1322 flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
1323
1324 ptr[i].xid = *xactptr;
1326 }
1327
1328 LWLockRelease(lock);
1329
1330 /*
1331 * Copy the result into the local cache.
1332 */
1333 mXactCachePut(multi, length, ptr);
1334
1335 debug_elog3(DEBUG2, "GetMembers: no cache for %s",
1336 mxid_to_string(multi, length, ptr));
1337 *members = ptr;
1338 return length;
1339}
uint32 TransactionId
Definition c.h:676
int errcode(int sqlerrcode)
Definition elog.c:863
int errmsg(const char *fmt,...)
Definition elog.c:1080
#define DEBUG2
Definition elog.h:29
#define ERROR
Definition elog.h:39
#define ereport(elevel,...)
Definition elog.h:150
int i
Definition isn.c:77
@ LW_SHARED
Definition lwlock.h:113
void * palloc(Size size)
Definition mcxt.c:1387
static int mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
Definition multixact.c:1422
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition multixact.c:2765
static void MultiXactIdSetOldestVisible(void)
Definition multixact.c:587
static void mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition multixact.c:1469
static MultiXactId NextMultiXactId(MultiXactId multi)
Definition multixact.c:102
#define debug_elog3(a, b, c)
Definition multixact.c:258
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition multixact.c:1537
#define debug_elog2(a, b)
Definition multixact.c:257
#define MXACT_MEMBER_XACT_BITMASK
static int MXOffsetToMemberOffset(MultiXactOffset32 offset)
#define ERRCODE_DATA_CORRUPTED
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition slru.c:527
TransactionId xid
Definition multixact.h:57
MultiXactStatus status
Definition multixact.h:58
MultiXactId nextMXact
Definition multixact.c:132
MultiXactId oldestMultiXactId
Definition multixact.c:145
#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(), MyProcNumber, NextMultiXactId(), MultiXactStateData::nextMXact, MultiXactStateData::oldestMultiXactId, OldestVisibleMXactId, 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 924 of file multixact.c.

925{
926 MultiXactId result;
927 MultiXactOffset nextOffset;
928
929 debug_elog3(DEBUG2, "GetNew: for %d xids", nmembers);
930
931 /* safety check, we should never get this far in a HS standby */
932 if (RecoveryInProgress())
933 elog(ERROR, "cannot assign MultiXactIds during recovery");
934
936
937 /* Assign the MXID */
938 result = MultiXactState->nextMXact;
939
940 /*----------
941 * Check to see if it's safe to assign another MultiXactId. This protects
942 * against catastrophic data loss due to multixact wraparound. The basic
943 * rules are:
944 *
945 * If we're past multiVacLimit or the safe threshold for member storage
946 * space, or we don't know what the safe threshold for member storage is,
947 * start trying to force autovacuum cycles.
948 * If we're past multiWarnLimit, start issuing warnings.
949 * If we're past multiStopLimit, refuse to create new MultiXactIds.
950 *
951 * Note these are pretty much the same protections in GetNewTransactionId.
952 *----------
953 */
955 {
956 /*
957 * For safety's sake, we release MultiXactGenLock while sending
958 * signals, warnings, etc. This is not so much because we care about
959 * preserving concurrency in this situation, as to avoid any
960 * possibility of deadlock while doing get_database_name(). First,
961 * copy all the shared values we'll need in this path.
962 */
963 MultiXactId multiWarnLimit = MultiXactState->multiWarnLimit;
964 MultiXactId multiStopLimit = MultiXactState->multiStopLimit;
965 MultiXactId multiWrapLimit = MultiXactState->multiWrapLimit;
967
969
970 if (IsUnderPostmaster &&
971 !MultiXactIdPrecedes(result, multiStopLimit))
972 {
974
975 /*
976 * Immediately kick autovacuum into action as we're already in
977 * ERROR territory.
978 */
980
981 /* complain even if that DB has disappeared */
982 if (oldest_datname)
985 errmsg("database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database \"%s\"",
987 errhint("Execute a database-wide VACUUM in that database.\n"
988 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
989 else
992 errmsg("database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database with OID %u",
994 errhint("Execute a database-wide VACUUM in that database.\n"
995 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
996 }
997
998 /*
999 * To avoid swamping the postmaster with signals, we issue the autovac
1000 * request only once per 64K multis generated. This still gives
1001 * plenty of chances before we get into real trouble.
1002 */
1003 if (IsUnderPostmaster && ((result % 65536) == 0 || result == FirstMultiXactId))
1005
1006 if (!MultiXactIdPrecedes(result, multiWarnLimit))
1007 {
1009
1010 /* complain even if that DB has disappeared */
1011 if (oldest_datname)
1013 (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
1014 "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
1015 multiWrapLimit - result,
1017 multiWrapLimit - result),
1018 errhint("Execute a database-wide VACUUM in that database.\n"
1019 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1020 else
1022 (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
1023 "database with OID %u must be vacuumed before %u more MultiXactIds are used",
1024 multiWrapLimit - result,
1026 multiWrapLimit - result),
1027 errhint("Execute a database-wide VACUUM in that database.\n"
1028 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1029 }
1030
1031 /* Re-acquire lock and start over */
1033 result = MultiXactState->nextMXact;
1034 }
1035
1036 /*
1037 * Make sure there is room for the next MXID in the file. Assigning this
1038 * MXID sets the next MXID's offset already.
1039 */
1041
1042 /*
1043 * Reserve the members space, similarly to above.
1044 */
1045 nextOffset = MultiXactState->nextOffset;
1046
1047 /*
1048 * Offsets are 64-bit integers and will never wrap around. Firstly, it
1049 * would take an unrealistic amount of time and resources to consume 2^64
1050 * offsets. Secondly, multixid creation is WAL-logged, so you would run
1051 * out of LSNs before reaching offset wraparound. Nevertheless, check for
1052 * wraparound as a sanity check.
1053 */
1054 if (nextOffset + nmembers < nextOffset)
1055 ereport(ERROR,
1057 errmsg("MultiXact members would wrap around")));
1058 *offset = nextOffset;
1059
1060 ExtendMultiXactMember(nextOffset, nmembers);
1061
1062 /*
1063 * Critical section from here until caller has written the data into the
1064 * just-reserved SLRU space; we don't want to error out with a partly
1065 * written MultiXact structure. (In particular, failing to write our
1066 * start offset after advancing nextMXact would effectively corrupt the
1067 * previous MultiXact.)
1068 */
1070
1071 /*
1072 * Advance counters. As in GetNewTransactionId(), this must not happen
1073 * until after file extension has succeeded!
1074 */
1076 MultiXactState->nextOffset += nmembers;
1077
1079
1080 debug_elog4(DEBUG2, "GetNew: returning %u offset %" PRIu64,
1081 result, *offset);
1082 return result;
1083}
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
Definition elog.c:1193
int errhint(const char *fmt,...)
Definition elog.c:1330
#define WARNING
Definition elog.h:36
#define elog(elevel,...)
Definition elog.h:226
bool IsUnderPostmaster
Definition globals.c:120
char * get_database_name(Oid dbid)
Definition lsyscache.c:1242
#define START_CRIT_SECTION()
Definition miscadmin.h:150
static void ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
Definition multixact.c:2242
static void ExtendMultiXactOffset(MultiXactId multi)
Definition multixact.c:2208
#define debug_elog4(a, b, c, d)
Definition multixact.c:259
void SendPostmasterSignal(PMSignalReason reason)
Definition pmsignal.c:165
@ PMSIGNAL_START_AUTOVAC_LAUNCHER
Definition pmsignal.h:39
unsigned int Oid
MultiXactId multiWrapLimit
Definition multixact.c:158
MultiXactId multiStopLimit
Definition multixact.c:157
MultiXactId multiWarnLimit
Definition multixact.c:156
MultiXactId multiVacLimit
Definition multixact.c:155
bool RecoveryInProgress(void)
Definition xlog.c:6461

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

Referenced by MultiXactIdCreateFromMembers().

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2303 of file multixact.c.

2304{
2306 int i;
2307
2308 /*
2309 * This is the oldest valid value among all the OldestMemberMXactId[] and
2310 * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2311 */
2314 for (i = 0; i < MaxOldestSlot; i++)
2315 {
2317
2326 }
2327
2329
2330 return oldestMXact;
2331}

References fb(), i, LW_SHARED, LWLockAcquire(), LWLockRelease(), MaxOldestSlot, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactState, MultiXactStateData::nextMXact, 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 2815 of file multixact.c.

2816{
2817 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2818
2819 /* Backup blocks are not used in multixact records */
2821
2822 if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
2823 {
2824 int64 pageno;
2825
2826 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
2828 }
2829 else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
2830 {
2831 int64 pageno;
2832
2833 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
2835 }
2836 else if (info == XLOG_MULTIXACT_CREATE_ID)
2837 {
2841 int i;
2842
2843 /* Store the data back into the SLRU files */
2844 RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
2845 xlrec->members);
2846
2847 /* Make sure nextMXact/nextOffset are beyond what this record has */
2849 xlrec->moff + xlrec->nmembers);
2850
2851 /*
2852 * Make sure nextXid is beyond any XID mentioned in the record. This
2853 * should be unnecessary, since any XID found here ought to have other
2854 * evidence in the XLOG, but let's be safe.
2855 */
2856 max_xid = XLogRecGetXid(record);
2857 for (i = 0; i < xlrec->nmembers; i++)
2858 {
2859 if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
2860 max_xid = xlrec->members[i].xid;
2861 }
2862
2864 }
2865 else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
2866 {
2868 int64 pageno;
2869
2870 memcpy(&xlrec, XLogRecGetData(record),
2872
2873 elog(DEBUG1, "replaying multixact truncation: "
2874 "oldestMulti %u (offsets segment %" PRIx64 "), "
2875 "oldestOffset %" PRIu64 " (members segment %" PRIx64 ")",
2876 xlrec.oldestMulti,
2877 MultiXactIdToOffsetSegment(xlrec.oldestMulti),
2878 xlrec.oldestOffset,
2879 MXOffsetToMemberSegment(xlrec.oldestOffset));
2880
2881 /* should not be required, but more than cheap enough */
2883
2884 /*
2885 * Advance the horizon values, so they're current at the end of
2886 * recovery.
2887 */
2888 SetMultiXactIdLimit(xlrec.oldestMulti, xlrec.oldestMultiDB);
2889
2890 PerformMembersTruncation(xlrec.oldestOffset);
2891
2892 /*
2893 * During XLOG replay, latest_page_number isn't necessarily set up
2894 * yet; insert a suitable value to bypass the sanity test in
2895 * SimpleLruTruncate.
2896 */
2897 pageno = MultiXactIdToOffsetPage(xlrec.oldestMulti);
2898 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2899 pageno);
2900 PerformOffsetsTruncation(xlrec.oldestMulti);
2901
2903 }
2904 else
2905 elog(PANIC, "multixact_redo: unknown op code %u", info);
2906}
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition atomics.h:485
uint8_t uint8
Definition c.h:554
#define PANIC
Definition elog.h:42
#define DEBUG1
Definition elog.h:30
static void PerformOffsetsTruncation(MultiXactId newOldestMulti)
Definition multixact.c:2574
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition multixact.c:757
static void PerformMembersTruncation(MultiXactOffset newOldestOffset)
Definition multixact.c:2564
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition multixact.c:2164
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
Definition multixact.c:2014
#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:304
#define XLogRecGetInfo(decoder)
Definition xlogreader.h:409
#define XLogRecGetData(decoder)
Definition xlogreader.h:414
#define XLogRecGetXid(decoder)
Definition xlogreader.h:411
#define XLogRecHasAnyBlockRefs(decoder)
Definition xlogreader.h:416

References AdvanceNextFullTransactionIdPastXid(), Assert, DEBUG1, elog, fb(), i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactAdvanceNextMXact(), MultiXactIdToOffsetPage(), MultiXactIdToOffsetSegment(), MultiXactMemberCtl, MultiXactOffsetCtl, MXOffsetToMemberSegment(), NextMultiXactId(), PANIC, PerformMembersTruncation(), PerformOffsetsTruncation(), pg_atomic_write_u64(), 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 1695 of file multixact.c.

1697{
1699}
void multixact_twophase_postcommit(FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
Definition multixact.c:1680
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 1680 of file multixact.c.

1682{
1684
1685 Assert(len == sizeof(MultiXactId));
1686
1688}
int ProcNumber
Definition procnumber.h:24
ProcNumber TwoPhaseGetDummyProcNumber(FullTransactionId fxid, bool lock_held)
Definition twophase.c:908

References Assert, fb(), InvalidMultiXactId, len, OldestMemberMXactId, 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 1659 of file multixact.c.

1661{
1664
1665 /*
1666 * Get the oldest member XID from the state file record, and set it in the
1667 * OldestMemberMXactId slot reserved for this prepared transaction.
1668 */
1669 Assert(len == sizeof(MultiXactId));
1671
1673}

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

◆ MultiXactAdvanceOldest()

void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2191 of file multixact.c.

2192{
2194
2196 SetMultiXactIdLimit(oldestMulti, oldestMultiDB);
2197}
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 1946 of file multixact.c.

1951{
1953 *nextMulti = MultiXactState->nextMXact;
1954 *nextMultiOffset = MultiXactState->nextOffset;
1955 *oldestMulti = MultiXactState->oldestMultiXactId;
1956 *oldestMultiDB = MultiXactState->oldestMultiXactDB;
1958
1960 "MultiXact: checkpoint is nextMulti %u, nextOffset %" PRIu64 ", oldestMulti %u in DB %u",
1961 *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
1962}
#define debug_elog6(a, b, c, d, e, f)
Definition multixact.c:261

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 299 of file multixact.c.

301{
303 MultiXactMember members[2];
304
307
309
310 /* MultiXactIdSetOldestMember() must have been called already. */
312
313 /*
314 * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs
315 * are still running. In typical usage, xid2 will be our own XID and the
316 * caller just did a check on xid1, so it'd be wasted effort.
317 */
318
319 members[0].xid = xid1;
320 members[0].status = status1;
321 members[1].xid = xid2;
322 members[1].status = status2;
323
325
326 debug_elog3(DEBUG2, "Create: %s",
327 mxid_to_string(newMulti, 2, members));
328
329 return newMulti;
330}
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
Definition multixact.c:656
#define TransactionIdEquals(id1, id2)
Definition transam.h:43

References Assert, DEBUG2, debug_elog3, fb(), MultiXactIdCreateFromMembers(), MultiXactIdIsValid, mxid_to_string(), MyProcNumber, OldestMemberMXactId, 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 656 of file multixact.c.

657{
658 MultiXactId multi;
659 MultiXactOffset offset;
661
662 debug_elog3(DEBUG2, "Create: %s",
663 mxid_to_string(InvalidMultiXactId, nmembers, members));
664
665 /*
666 * See if the same set of members already exists in our cache; if so, just
667 * re-use that MultiXactId. (Note: it might seem that looking in our
668 * cache is insufficient, and we ought to search disk to see if a
669 * duplicate definition already exists. But since we only ever create
670 * MultiXacts containing our own XID, in most cases any such MultiXacts
671 * were in fact created by us, and so will be in our cache. There are
672 * corner cases where someone else added us to a MultiXact without our
673 * knowledge, but it's not worth checking for.)
674 */
675 multi = mXactCacheGetBySet(nmembers, members);
676 if (MultiXactIdIsValid(multi))
677 {
678 debug_elog2(DEBUG2, "Create: in cache!");
679 return multi;
680 }
681
682 /* Verify that there is a single update Xid among the given members. */
683 {
684 int i;
685 bool has_update = false;
686
687 for (i = 0; i < nmembers; i++)
688 {
689 if (ISUPDATE_from_mxstatus(members[i].status))
690 {
691 if (has_update)
692 elog(ERROR, "new multixact has more than one updating member: %s",
693 mxid_to_string(InvalidMultiXactId, nmembers, members));
694 has_update = true;
695 }
696 }
697 }
698
699 /* Load the injection point before entering the critical section */
700 INJECTION_POINT_LOAD("multixact-create-from-members");
701
702 /*
703 * Assign the MXID and offsets range to use, and make sure there is space
704 * in the OFFSETs and MEMBERs files. NB: this routine does
705 * START_CRIT_SECTION().
706 *
707 * Note: unlike MultiXactIdCreate and MultiXactIdExpand, we do not check
708 * that we've called MultiXactIdSetOldestMember here. This is because
709 * this routine is used in some places to create new MultiXactIds of which
710 * the current backend is not a member, notably during freezing of multis
711 * in vacuum. During vacuum, in particular, it would be unacceptable to
712 * keep OldestMulti set, in case it runs for long.
713 */
714 multi = GetNewMultiXactId(nmembers, &offset);
715
716 INJECTION_POINT_CACHED("multixact-create-from-members", NULL);
717
718 /* Make an XLOG entry describing the new MXID. */
719 xlrec.mid = multi;
720 xlrec.moff = offset;
721 xlrec.nmembers = nmembers;
722
723 /*
724 * XXX Note: there's a lot of padding space in MultiXactMember. We could
725 * find a more compact representation of this Xlog record -- perhaps all
726 * the status flags in one XLogRecData, then all the xids in another one?
727 * Not clear that it's worth the trouble though.
728 */
731 XLogRegisterData(members, nmembers * sizeof(MultiXactMember));
732
734
735 /* Now enter the information into the OFFSETs and MEMBERs logs */
736 RecordNewMultiXact(multi, offset, nmembers, members);
737
738 /* Done with critical section */
740
741 /* Store the new MultiXactId in the local cache, too */
742 mXactCachePut(multi, nmembers, members);
743
744 debug_elog2(DEBUG2, "Create: all done");
745
746 return multi;
747}
#define INJECTION_POINT_CACHED(name, arg)
#define INJECTION_POINT_LOAD(name)
#define END_CRIT_SECTION()
Definition miscadmin.h:152
static MultiXactId GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
Definition multixact.c:924
static MultiXactId mXactCacheGetBySet(int nmembers, MultiXactMember *members)
Definition multixact.c:1379
#define ISUPDATE_from_mxstatus(status)
Definition multixact.h:51
#define SizeOfMultiXactCreate
Definition multixact.h:80
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
Definition xloginsert.c:478
void XLogRegisterData(const void *data, uint32 len)
Definition xloginsert.c:368
void XLogBeginInsert(void)
Definition xloginsert.c:152

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 352 of file multixact.c.

353{
355 MultiXactMember *members;
357 int nmembers;
358 int i;
359 int j;
360
363
364 /* MultiXactIdSetOldestMember() must have been called already. */
366
367 debug_elog5(DEBUG2, "Expand: received multi %u, xid %u status %s",
368 multi, xid, mxstatus_to_string(status));
369
370 /*
371 * Note: we don't allow for old multis here. The reason is that the only
372 * caller of this function does a check that the multixact is no longer
373 * running.
374 */
375 nmembers = GetMultiXactIdMembers(multi, &members, false, false);
376
377 if (nmembers < 0)
378 {
379 MultiXactMember member;
380
381 /*
382 * The MultiXactId is obsolete. This can only happen if all the
383 * MultiXactId members stop running between the caller checking and
384 * passing it to us. It would be better to return that fact to the
385 * caller, but it would complicate the API and it's unlikely to happen
386 * too often, so just deal with it by creating a singleton MultiXact.
387 */
388 member.xid = xid;
389 member.status = status;
391
392 debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u",
393 multi, newMulti);
394 return newMulti;
395 }
396
397 /*
398 * If the TransactionId is already a member of the MultiXactId with the
399 * same status, just return the existing MultiXactId.
400 */
401 for (i = 0; i < nmembers; i++)
402 {
403 if (TransactionIdEquals(members[i].xid, xid) &&
404 (members[i].status == status))
405 {
406 debug_elog4(DEBUG2, "Expand: %u is already a member of %u",
407 xid, multi);
408 pfree(members);
409 return multi;
410 }
411 }
412
413 /*
414 * Determine which of the members of the MultiXactId are still of
415 * interest. This is any running transaction, and also any transaction
416 * that grabbed something stronger than just a lock and was committed. (An
417 * update that aborted is of no interest here; and having more than one
418 * update Xid in a multixact would cause errors elsewhere.)
419 *
420 * Removing dead members is not just an optimization: freezing of tuples
421 * whose Xmax are multis depends on this behavior.
422 *
423 * Note we have the same race condition here as above: j could be 0 at the
424 * end of the loop.
425 */
426 newMembers = palloc_array(MultiXactMember, nmembers + 1);
427
428 for (i = 0, j = 0; i < nmembers; i++)
429 {
430 if (TransactionIdIsInProgress(members[i].xid) ||
431 (ISUPDATE_from_mxstatus(members[i].status) &&
432 TransactionIdDidCommit(members[i].xid)))
433 {
434 newMembers[j].xid = members[i].xid;
435 newMembers[j++].status = members[i].status;
436 }
437 }
438
439 newMembers[j].xid = xid;
440 newMembers[j++].status = status;
442
443 pfree(members);
445
446 debug_elog3(DEBUG2, "Expand: returning new multi %u", newMulti);
447
448 return newMulti;
449}
#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:1514
#define debug_elog5(a, b, c, d, e)
Definition multixact.c:260
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool isLockOnly)
Definition multixact.c:1113
bool TransactionIdIsInProgress(TransactionId xid)
Definition procarray.c:1404
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(), MyProcNumber, OldestMemberMXactId, 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 463 of file multixact.c.

464{
465 MultiXactMember *members;
466 int nmembers;
467 int i;
468
469 debug_elog3(DEBUG2, "IsRunning %u?", multi);
470
471 /*
472 * "false" here means we assume our callers have checked that the given
473 * multi cannot possibly come from a pg_upgraded database.
474 */
475 nmembers = GetMultiXactIdMembers(multi, &members, false, isLockOnly);
476
477 if (nmembers <= 0)
478 {
479 debug_elog2(DEBUG2, "IsRunning: no members");
480 return false;
481 }
482
483 /*
484 * Checking for myself is cheap compared to looking in shared memory;
485 * return true if any live subtransaction of the current top-level
486 * transaction is a member.
487 *
488 * This is not needed for correctness, it's just a fast path.
489 */
490 for (i = 0; i < nmembers; i++)
491 {
492 if (TransactionIdIsCurrentTransactionId(members[i].xid))
493 {
494 debug_elog3(DEBUG2, "IsRunning: I (%d) am running!", i);
495 pfree(members);
496 return true;
497 }
498 }
499
500 /*
501 * This could be made faster by having another entry point in procarray.c,
502 * walking the PGPROC array only once for all the members. But in most
503 * cases nmembers should be small enough that it doesn't much matter.
504 */
505 for (i = 0; i < nmembers; i++)
506 {
507 if (TransactionIdIsInProgress(members[i].xid))
508 {
509 debug_elog4(DEBUG2, "IsRunning: member %d (%u) is running",
510 i, members[i].xid);
511 pfree(members);
512 return true;
513 }
514 }
515
516 pfree(members);
517
518 debug_elog3(DEBUG2, "IsRunning: %u is not running", multi);
519
520 return false;
521}
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
Definition xact.c:942

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 2779 of file multixact.c.

2780{
2781 int32 diff = (int32) (multi1 - multi2);
2782
2783 return (diff <= 0);
2784}

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 537 of file multixact.c.

538{
540 {
541 MultiXactId nextMXact;
542
543 /*
544 * You might think we don't need to acquire a lock here, since
545 * fetching and storing of TransactionIds is probably atomic, but in
546 * fact we do: suppose we pick up nextMXact and then lose the CPU for
547 * a long time. Someone else could advance nextMXact, and then
548 * another someone else could compute an OldestVisibleMXactId that
549 * would be after the value we are going to store when we get control
550 * back. Which would be wrong.
551 *
552 * Note that a shared lock is sufficient, because it's enough to stop
553 * someone from advancing nextMXact; and nobody else could be trying
554 * to write to our OldestMember entry, only reading (and we assume
555 * storing it is atomic.)
556 */
558
559 nextMXact = MultiXactState->nextMXact;
560
562
564
565 debug_elog4(DEBUG2, "MultiXact: setting OldestMember[%d] = %u",
566 MyProcNumber, nextMXact);
567 }
568}

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

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 2511 of file multixact.c.

2512{
2515 double fraction;
2516 int result;
2517 MultiXactId oldestMultiXactId;
2518 MultiXactOffset oldestOffset;
2519 MultiXactOffset nextOffset;
2520 uint64 members;
2521
2522 /* Read the current offsets and multixact usage. */
2523 GetMultiXactInfo(&multixacts, &nextOffset, &oldestMultiXactId, &oldestOffset);
2524 members = nextOffset - oldestOffset;
2525
2526 /* If member space utilization is low, no special action is required. */
2527 if (members <= MULTIXACT_MEMBER_LOW_THRESHOLD)
2529
2530 /*
2531 * Compute a target for relminmxid advancement. The number of multixacts
2532 * we try to eliminate from the system is based on how far we are past
2533 * MULTIXACT_MEMBER_LOW_THRESHOLD.
2534 *
2535 * The way this formula works is that when members is exactly at the low
2536 * threshold, fraction = 0.0, and we set freeze_max_age equal to
2537 * mxid_age(oldestMultiXactId). As members grows further, towards the
2538 * high threshold, fraction grows linearly from 0.0 to 1.0, and the result
2539 * shrinks from mxid_age(oldestMultiXactId) to 0. Beyond the high
2540 * threshold, fraction > 1.0 and the result is clamped to 0.
2541 */
2544
2545 /* fraction could be > 1.0, but lowest possible freeze age is zero */
2546 if (fraction >= 1.0)
2547 return 0;
2548
2550 result = multixacts - victim_multixacts;
2551
2552 /*
2553 * Clamp to autovacuum_multixact_freeze_max_age, so that we never make
2554 * autovacuum less aggressive than it would otherwise be.
2555 */
2557}
int autovacuum_multixact_freeze_max_age
Definition autovacuum.c:130
#define Min(x, y)
Definition c.h:1007
uint64_t uint64
Definition c.h:557
void GetMultiXactInfo(uint32 *multixacts, MultiXactOffset *nextOffset, MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset)
Definition multixact.c:2467
#define MULTIXACT_MEMBER_LOW_THRESHOLD
Definition multixact.c:98
#define MULTIXACT_MEMBER_HIGH_THRESHOLD
Definition multixact.c:99

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

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

◆ MultiXactMemberPagePrecedes()

static bool MultiXactMemberPagePrecedes ( int64  page1,
int64  page2 
)
static

Definition at line 2753 of file multixact.c.

2754{
2755 return page1 < page2;
2756}

References fb().

Referenced by MultiXactShmemInit().

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char path 
)

Definition at line 2921 of file multixact.c.

2922{
2923 return SlruSyncFileTag(MultiXactMemberCtl, ftag, path);
2924}
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
Definition slru.c:1856

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ MultiXactOffsetPagePrecedes()

static bool MultiXactOffsetPagePrecedes ( int64  page1,
int64  page2 
)
static

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char path 
)

Definition at line 2912 of file multixact.c.

2913{
2914 return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
2915}

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 1992 of file multixact.c.

1994{
1995 Assert(MultiXactIdIsValid(nextMulti));
1996 debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %" PRIu64,
1997 nextMulti, nextMultiOffset);
1998
2000 MultiXactState->nextMXact = nextMulti;
2001 MultiXactState->nextOffset = nextMultiOffset;
2003}

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

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

◆ MultiXactShmemInit()

void MultiXactShmemInit ( void  )

Definition at line 1724 of file multixact.c.

1725{
1726 bool found;
1727
1728 debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1729
1732
1734 "multixact_offset", multixact_offset_buffers, 0,
1735 "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1738 false);
1741 "multixact_member", multixact_member_buffers, 0,
1742 "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1745 true);
1746 /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1747
1748 /* Initialize our shared state struct */
1749 MultiXactState = ShmemInitStruct("Shared MultiXact State",
1751 &found);
1752 if (!IsUnderPostmaster)
1753 {
1754 Assert(!found);
1755
1756 /* Make sure we zero out the per-backend state */
1758 }
1759 else
1760 Assert(found);
1761
1762 /*
1763 * Set up array pointers.
1764 */
1767}
#define MemSet(start, val, len)
Definition c.h:1023
int multixact_offset_buffers
Definition globals.c:163
int multixact_member_buffers
Definition globals.c:162
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
Definition multixact.c:2753
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition multixact.c:2732
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
Definition shmem.c:389
void SimpleLruInit(SlruCtl ctl, const char *name, int nslots, int nlsns, const char *subdir, int buffer_tranche_id, int bank_tranche_id, SyncRequestHandler sync_handler, bool long_segment_names)
Definition slru.c:252
#define SlruPagePrecedesUnitTests(ctl, per_page)
Definition slru.h:185
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
Definition multixact.c:207
@ SYNC_HANDLER_MULTIXACT_MEMBER
Definition sync.h:41
@ SYNC_HANDLER_MULTIXACT_OFFSET
Definition sync.h:40

References Assert, DEBUG2, debug_elog2, fb(), IsUnderPostmaster, MaxOldestSlot, MemSet, multixact_member_buffers, multixact_offset_buffers, MULTIXACT_OFFSETS_PER_PAGE, MultiXactMemberCtl, MultiXactMemberPagePrecedes(), MultiXactOffsetCtl, MultiXactOffsetPagePrecedes(), MultiXactState, OldestMemberMXactId, OldestVisibleMXactId, MultiXactStateData::perBackendXactIds, SHARED_MULTIXACT_STATE_SIZE, ShmemInitStruct(), SimpleLruInit(), SlruPagePrecedesUnitTests, SYNC_HANDLER_MULTIXACT_MEMBER, and SYNC_HANDLER_MULTIXACT_OFFSET.

Referenced by CreateOrAttachShmemStructs().

◆ MultiXactShmemSize()

Size MultiXactShmemSize ( void  )

Definition at line 1707 of file multixact.c.

1708{
1709 Size size;
1710
1711 /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1712#define SHARED_MULTIXACT_STATE_SIZE \
1713 add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1714 mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1715
1719
1720 return size;
1721}
size_t Size
Definition c.h:629
Size SimpleLruShmemSize(int nslots, int nlsns)
Definition slru.c:198

References add_size(), multixact_member_buffers, multixact_offset_buffers, SHARED_MULTIXACT_STATE_SIZE, and SimpleLruShmemSize().

Referenced by CalculateShmemSize().

◆ mXactCacheGetById()

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

Definition at line 1422 of file multixact.c.

1423{
1424 dlist_iter iter;
1425
1426 debug_elog3(DEBUG2, "CacheGet: looking for %u", multi);
1427
1429 {
1431 iter.cur);
1432
1433 if (entry->multi == multi)
1434 {
1435 MultiXactMember *ptr;
1436 Size size;
1437
1438 size = sizeof(MultiXactMember) * entry->nmembers;
1439 ptr = (MultiXactMember *) palloc(size);
1440
1441 memcpy(ptr, entry->members, size);
1442
1443 debug_elog3(DEBUG2, "CacheGet: found %s",
1444 mxid_to_string(multi,
1445 entry->nmembers,
1446 entry->members));
1447
1448 /*
1449 * Note we modify the list while not using a modifiable iterator.
1450 * This is acceptable only because we exit the iteration
1451 * immediately afterwards.
1452 */
1454
1455 *members = ptr;
1456 return entry->nmembers;
1457 }
1458 }
1459
1460 debug_elog2(DEBUG2, "CacheGet: not found");
1461 return -1;
1462}
#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:240
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
Definition multixact.c:243

References dlist_iter::cur, dclist_container, dclist_foreach, dclist_move_head(), DEBUG2, debug_elog2, debug_elog3, fb(), mXactCacheEnt::members, 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 1379 of file multixact.c.

1380{
1381 dlist_iter iter;
1382
1383 debug_elog3(DEBUG2, "CacheGet: looking for %s",
1384 mxid_to_string(InvalidMultiXactId, nmembers, members));
1385
1386 /* sort the array so comparison is easy */
1387 qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1388
1390 {
1392 iter.cur);
1393
1394 if (entry->nmembers != nmembers)
1395 continue;
1396
1397 /*
1398 * We assume the cache entries are sorted, and that the unused bits in
1399 * "status" are zeroed.
1400 */
1401 if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0)
1402 {
1403 debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi);
1405 return entry->multi;
1406 }
1407 }
1408
1409 debug_elog2(DEBUG2, "CacheGet: not found :-(");
1410 return InvalidMultiXactId;
1411}
static int mxactMemberComparator(const void *arg1, const void *arg2)
Definition multixact.c:1349
#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 1469 of file multixact.c.

1470{
1471 mXactCacheEnt *entry;
1472
1473 debug_elog3(DEBUG2, "CachePut: storing %s",
1474 mxid_to_string(multi, nmembers, members));
1475
1476 if (MXactContext == NULL)
1477 {
1478 /* The cache only lives as long as the current transaction */
1479 debug_elog2(DEBUG2, "CachePut: initializing memory context");
1481 "MultiXact cache context",
1483 }
1484
1485 entry = (mXactCacheEnt *)
1487 offsetof(mXactCacheEnt, members) +
1488 nmembers * sizeof(MultiXactMember));
1489
1490 entry->multi = multi;
1491 entry->nmembers = nmembers;
1492 memcpy(entry->members, members, nmembers * sizeof(MultiXactMember));
1493
1494 /* mXactCacheGetBySet assumes the entries are sorted, so sort them */
1495 qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator);
1496
1497 dclist_push_head(&MXactCache, &entry->node);
1499 {
1500 dlist_node *node;
1501
1504
1505 entry = dclist_container(mXactCacheEnt, node, node);
1506 debug_elog3(DEBUG2, "CachePut: pruning cached multi %u",
1507 entry->multi);
1508
1509 pfree(entry);
1510 }
1511}
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:246
dlist_node node
Definition multixact.c:242

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, 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 1349 of file multixact.c.

1350{
1353
1354 if (member1.xid > member2.xid)
1355 return 1;
1356 if (member1.xid < member2.xid)
1357 return -1;
1358 if (member1.status > member2.status)
1359 return 1;
1360 if (member1.status < member2.status)
1361 return -1;
1362 return 0;
1363}

References fb().

Referenced by mXactCacheGetBySet(), and mXactCachePut().

◆ mxid_to_string()

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

Definition at line 1537 of file multixact.c.

1538{
1539 static char *str = NULL;
1541 int i;
1542
1543 if (str != NULL)
1544 pfree(str);
1545
1547
1548 appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1549 mxstatus_to_string(members[0].status));
1550
1551 for (i = 1; i < nmembers; i++)
1552 appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1553 mxstatus_to_string(members[i].status));
1554
1557 pfree(buf.data);
1558 return str;
1559}
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 1514 of file multixact.c.

1515{
1516 switch (status)
1517 {
1519 return "keysh";
1521 return "sh";
1523 return "fornokeyupd";
1525 return "forupd";
1527 return "nokeyupd";
1529 return "upd";
1530 default:
1531 elog(ERROR, "unrecognized multixact status %d", status);
1532 return "";
1533 }
1534}
@ 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().

◆ NextMultiXactId()

static MultiXactId NextMultiXactId ( MultiXactId  multi)
inlinestatic

Definition at line 102 of file multixact.c.

103{
104 return multi == MaxMultiXactId ? FirstMultiXactId : multi + 1;
105}
#define MaxMultiXactId
Definition multixact.h:27

References FirstMultiXactId, and MaxMultiXactId.

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

◆ PerformMembersTruncation()

static void PerformMembersTruncation ( MultiXactOffset  newOldestOffset)
static

Definition at line 2564 of file multixact.c.

2565{
2568}
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Definition slru.c:1433

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

Referenced by multixact_redo(), and TruncateMultiXact().

◆ PerformOffsetsTruncation()

static void PerformOffsetsTruncation ( MultiXactId  newOldestMulti)
static

Definition at line 2574 of file multixact.c.

2575{
2576 /*
2577 * We step back one multixact to avoid passing a cutoff page that hasn't
2578 * been created yet in the rare case that oldestMulti would be the first
2579 * item on a page and oldestMulti == nextMulti. In that case, if we
2580 * didn't subtract one, we'd trigger SimpleLruTruncate's wraparound
2581 * detection.
2582 */
2585}
static MultiXactId PreviousMultiXactId(MultiXactId multi)
Definition multixact.c:108

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

Referenced by multixact_redo(), and TruncateMultiXact().

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( FullTransactionId  fxid)

Definition at line 1610 of file multixact.c.

1611{
1613
1614 /*
1615 * Transfer our OldestMemberMXactId value to the slot reserved for the
1616 * prepared transaction.
1617 */
1620 {
1622
1623 /*
1624 * Even though storing MultiXactId is atomic, acquire lock to make
1625 * sure others see both changes, not just the reset of the slot of the
1626 * current backend. Using a volatile pointer might suffice, but this
1627 * isn't a hot spot.
1628 */
1630
1633
1635 }
1636
1637 /*
1638 * We don't need to transfer OldestVisibleMXactId value, because the
1639 * transaction is not going to be looking at any more multixacts once it's
1640 * prepared.
1641 *
1642 * We assume that storing a MultiXactId is atomic and so we need not take
1643 * MultiXactGenLock to do this.
1644 */
1646
1647 /*
1648 * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1649 */
1652}

References dclist_init(), fb(), InvalidMultiXactId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdIsValid, MXactCache, MXactContext, MyProcNumber, OldestMemberMXactId, OldestVisibleMXactId, and TwoPhaseGetDummyProcNumber().

Referenced by PrepareTransaction().

◆ PreviousMultiXactId()

static MultiXactId PreviousMultiXactId ( MultiXactId  multi)
inlinestatic

Definition at line 108 of file multixact.c.

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

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 757 of file multixact.c.

759{
760 int64 pageno;
762 int entryno;
763 int slotno;
767 int next_entryno;
770 LWLock *lock;
772
773 /* position of this multixid in the offsets SLRU area */
774 pageno = MultiXactIdToOffsetPage(multi);
776
777 /* position of the next multixid */
778 next = NextMultiXactId(multi);
781
782 /*
783 * Set the starting offset of this multixid's members.
784 *
785 * In the common case, it was already be set by the previous
786 * RecordNewMultiXact call, as this was the next multixid of the previous
787 * multixid. But if multiple backends are generating multixids
788 * concurrently, we might race ahead and get called before the previous
789 * multixid.
790 */
793
794 /*
795 * Note: we pass the MultiXactId to SimpleLruReadPage as the "transaction"
796 * to complain about if there's any I/O error. This is kinda bogus, but
797 * since the errors will always give the full pathname, it should be clear
798 * enough that a MultiXactId is really involved. Perhaps someday we'll
799 * take the trouble to generalize the slru.c error reporting code.
800 */
801 slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
802 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
803 offptr += entryno;
804
805 if (*offptr != offset)
806 {
807 /* should already be set to the correct value, or not at all */
808 Assert(*offptr == 0);
809 *offptr = offset;
810 MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
811 }
812
813 /*
814 * Set the next multixid's offset to the end of this multixid's members.
815 */
816 if (next_pageno == pageno)
817 {
818 next_offptr = offptr + 1;
819 }
820 else
821 {
822 /* must be the first entry on the page */
824
825 /* Swap the lock for a lock on the next page */
826 LWLockRelease(lock);
829
831 next_offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
833 }
834
835 /* Like in GetNewMultiXactId(), skip over offset 0 */
836 next_offset = offset + nmembers;
837 if (next_offset == 0)
838 next_offset = 1;
839 if (*next_offptr != next_offset)
840 {
841 /* should already be set to the correct value, or not at all */
842 Assert(*next_offptr == 0);
844 MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
845 }
846
847 /* Release MultiXactOffset SLRU lock. */
848 LWLockRelease(lock);
849
850 prev_pageno = -1;
851
852 for (int i = 0; i < nmembers; i++, offset++)
853 {
857 int bshift;
858 int flagsoff;
859 int memberoff;
860
861 Assert(members[i].status <= MultiXactStatusUpdate);
862
863 pageno = MXOffsetToMemberPage(offset);
867
868 if (pageno != prev_pageno)
869 {
870 /*
871 * MultiXactMember SLRU page is changed so check if this new page
872 * fall into the different SLRU bank then release the old bank's
873 * lock and acquire lock on the new bank.
874 */
876 if (lock != prevlock)
877 {
878 if (prevlock != NULL)
880
882 prevlock = lock;
883 }
884 slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
885 prev_pageno = pageno;
886 }
887
889 (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
890
891 *memberptr = members[i].xid;
892
893 flagsptr = (uint32 *)
894 (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
895
897 flagsval &= ~(((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) << bshift);
898 flagsval |= (members[i].status << bshift);
900
901 MultiXactMemberCtl->shared->page_dirty[slotno] = true;
902 }
903
904 if (prevlock != NULL)
906}
#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 2014 of file multixact.c.

2015{
2016 MultiXactId multiVacLimit;
2017 MultiXactId multiWarnLimit;
2018 MultiXactId multiStopLimit;
2019 MultiXactId multiWrapLimit;
2021
2023
2024 /*
2025 * We pretend that a wrap will happen halfway through the multixact ID
2026 * space, but that's not really true, because multixacts wrap differently
2027 * from transaction IDs.
2028 */
2029 multiWrapLimit = oldest_datminmxid + (MaxMultiXactId >> 1);
2030 if (multiWrapLimit < FirstMultiXactId)
2031 multiWrapLimit += FirstMultiXactId;
2032
2033 /*
2034 * We'll refuse to continue assigning MultiXactIds once we get within 3M
2035 * multi of data loss. See SetTransactionIdLimit.
2036 */
2037 multiStopLimit = multiWrapLimit - 3000000;
2038 if (multiStopLimit < FirstMultiXactId)
2039 multiStopLimit -= FirstMultiXactId;
2040
2041 /*
2042 * We'll start complaining loudly when we get within 40M multis of data
2043 * loss. This is kind of arbitrary, but if you let your gas gauge get
2044 * down to 2% of full, would you be looking for the next gas station? We
2045 * need to be fairly liberal about this number because there are lots of
2046 * scenarios where most transactions are done by automatic clients that
2047 * won't pay attention to warnings. (No, we're not gonna make this
2048 * configurable. If you know enough to configure it, you know enough to
2049 * not get in this kind of trouble in the first place.)
2050 */
2051 multiWarnLimit = multiWrapLimit - 40000000;
2052 if (multiWarnLimit < FirstMultiXactId)
2053 multiWarnLimit -= FirstMultiXactId;
2054
2055 /*
2056 * We'll start trying to force autovacuums when oldest_datminmxid gets to
2057 * be more than autovacuum_multixact_freeze_max_age mxids old.
2058 *
2059 * Note: autovacuum_multixact_freeze_max_age is a PGC_POSTMASTER parameter
2060 * so that we don't have to worry about dealing with on-the-fly changes in
2061 * its value. See SetTransactionIdLimit.
2062 */
2064 if (multiVacLimit < FirstMultiXactId)
2065 multiVacLimit += FirstMultiXactId;
2066
2067 /* Grab lock for just long enough to set the new limit values */
2071 MultiXactState->multiVacLimit = multiVacLimit;
2072 MultiXactState->multiWarnLimit = multiWarnLimit;
2073 MultiXactState->multiStopLimit = multiStopLimit;
2074 MultiXactState->multiWrapLimit = multiWrapLimit;
2077
2078 /* Log the info */
2080 (errmsg_internal("MultiXactId wrap limit is %u, limited by database with OID %u",
2081 multiWrapLimit, oldest_datoid)));
2082
2083 /*
2084 * Computing the actual limits is only possible once the data directory is
2085 * in a consistent state. There's no need to compute the limits while
2086 * still replaying WAL - no decisions about new multis are made even
2087 * though multixact creations might be replayed. So we'll only do further
2088 * checks after TrimMultiXact() has been called.
2089 */
2091 return;
2092
2094
2095 /*
2096 * Offsets are 64-bits wide and never wrap around, so we don't need to
2097 * consider them for emergency autovacuum purposes. But now that we're in
2098 * a consistent state, determine MultiXactState->oldestOffset. It will be
2099 * used to adjust the freezing cutoff, to keep the offsets disk usage in
2100 * check.
2101 */
2103
2104 /*
2105 * If past the autovacuum force point, immediately signal an autovac
2106 * request. The reason for this is that autovac only processes one
2107 * database per invocation. Once it's finished cleaning up the oldest
2108 * database, it'll call here, and we'll signal the postmaster to start
2109 * another iteration immediately if there are still any old databases.
2110 */
2111 if (MultiXactIdPrecedes(multiVacLimit, curMulti) && IsUnderPostmaster)
2113
2114 /* Give an immediate warning if past the wrap warn point */
2115 if (MultiXactIdPrecedes(multiWarnLimit, curMulti))
2116 {
2117 char *oldest_datname;
2118
2119 /*
2120 * We can be called when not inside a transaction, for example during
2121 * StartupXLOG(). In such a case we cannot do database access, so we
2122 * must just report the oldest DB's OID.
2123 *
2124 * Note: it's also possible that get_database_name fails and returns
2125 * NULL, for example because the database just got dropped. We'll
2126 * still warn, even though the warning might now be unnecessary.
2127 */
2128 if (IsTransactionState())
2130 else
2132
2133 if (oldest_datname)
2135 (errmsg_plural("database \"%s\" must be vacuumed before %u more MultiXactId is used",
2136 "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
2137 multiWrapLimit - curMulti,
2139 multiWrapLimit - curMulti),
2140 errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2141 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2142 else
2144 (errmsg_plural("database with OID %u must be vacuumed before %u more MultiXactId is used",
2145 "database with OID %u must be vacuumed before %u more MultiXactIds are used",
2146 multiWrapLimit - curMulti,
2148 multiWrapLimit - curMulti),
2149 errhint("To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2150 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2151 }
2152}
int errmsg_internal(const char *fmt,...)
Definition elog.c:1170
static void SetOldestOffset(void)
Definition multixact.c:2338
bool IsTransactionState(void)
Definition xact.c:388

References Assert, autovacuum_multixact_freeze_max_age, DEBUG1, ereport, 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 2338 of file multixact.c.

2339{
2340 MultiXactId oldestMultiXactId;
2341 MultiXactId nextMXact;
2342 MultiXactOffset oldestOffset = 0; /* placate compiler */
2343 MultiXactOffset nextOffset;
2344 bool oldestOffsetKnown = false;
2345
2346 /*
2347 * NB: Have to prevent concurrent truncation, we might otherwise try to
2348 * lookup an oldestMulti that's concurrently getting truncated away.
2349 */
2351
2352 /* Read relevant fields from shared memory. */
2354 oldestMultiXactId = MultiXactState->oldestMultiXactId;
2355 nextMXact = MultiXactState->nextMXact;
2356 nextOffset = MultiXactState->nextOffset;
2359
2360 /*
2361 * Determine the offset of the oldest multixact. Normally, we can read
2362 * the offset from the multixact itself, but there's an important special
2363 * case: if there are no multixacts in existence at all, oldestMXact
2364 * obviously can't point to one. It will instead point to the multixact
2365 * ID that will be assigned the next time one is needed.
2366 */
2367 if (oldestMultiXactId == nextMXact)
2368 {
2369 /*
2370 * When the next multixact gets created, it will be stored at the next
2371 * offset.
2372 */
2373 oldestOffset = nextOffset;
2374 oldestOffsetKnown = true;
2375 }
2376 else
2377 {
2378 /*
2379 * Look up the offset at which the oldest existing multixact's members
2380 * are stored. If we cannot find it, be careful not to fail, and
2381 * leave oldestOffset unchanged. oldestOffset is initialized to zero
2382 * at system startup, which prevents truncating members until a proper
2383 * value is calculated.
2384 *
2385 * (We had bugs in early releases of PostgreSQL 9.3.X and 9.4.X where
2386 * the supposedly-earliest multixact might not really exist. Those
2387 * should be long gone by now, so this should not fail, but let's
2388 * still be defensive.)
2389 */
2391 find_multixact_start(oldestMultiXactId, &oldestOffset);
2392
2395 (errmsg_internal("oldest MultiXactId member is at offset %" PRIu64,
2396 oldestOffset)));
2397 else
2398 ereport(LOG,
2399 (errmsg("MultiXact member truncation is disabled because oldest checkpointed MultiXact %u does not exist on disk",
2400 oldestMultiXactId)));
2401 }
2402
2404
2405 /* Install the computed value */
2407 {
2409 MultiXactState->oldestOffset = oldestOffset;
2411 }
2412}
#define LOG
Definition elog.h:31
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result)
Definition multixact.c:2424

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 1809 of file multixact.c.

1810{
1813 int64 pageno;
1814
1815 /*
1816 * Initialize offset's idea of the latest page number.
1817 */
1818 pageno = MultiXactIdToOffsetPage(multi);
1819 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
1820 pageno);
1821
1822 /*
1823 * Initialize member's idea of the latest page number.
1824 */
1825 pageno = MXOffsetToMemberPage(offset);
1826 pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
1827 pageno);
1828}

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 1834 of file multixact.c.

1835{
1836 MultiXactId nextMXact;
1837 MultiXactOffset offset;
1840 int64 pageno;
1841 int entryno;
1842 int flagsoff;
1843
1845 nextMXact = MultiXactState->nextMXact;
1846 offset = MultiXactState->nextOffset;
1850
1851 /* Clean up offsets state */
1852
1853 /*
1854 * (Re-)Initialize our idea of the latest page number for offsets.
1855 */
1856 pageno = MultiXactIdToOffsetPage(nextMXact);
1857 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
1858 pageno);
1859
1860 /*
1861 * Set the offset of nextMXact on the offsets page. This is normally done
1862 * in RecordNewMultiXact() of the previous multixact, but let's be sure
1863 * the next page exists, if the nextMXact was reset with pg_resetwal for
1864 * example.
1865 *
1866 * Zero out the remainder of the page. See notes in TrimCLOG() for
1867 * background. Unlike CLOG, some WAL record covers every pg_multixact
1868 * SLRU mutation. Since, also unlike CLOG, we ignore the WAL rule "write
1869 * xlog before data," nextMXact successors may carry obsolete, nonzero
1870 * offset values.
1871 */
1872 entryno = MultiXactIdToOffsetEntry(nextMXact);
1873 {
1874 int slotno;
1877
1879 if (entryno == 0 || nextMXact == FirstMultiXactId)
1881 else
1882 slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, nextMXact);
1883 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1884 offptr += entryno;
1885
1886 *offptr = offset;
1887 if (entryno != 0 && (entryno + 1) * sizeof(MultiXactOffset) != BLCKSZ)
1888 MemSet(offptr + 1, 0, BLCKSZ - (entryno + 1) * sizeof(MultiXactOffset));
1889
1890 MultiXactOffsetCtl->shared->page_dirty[slotno] = true;
1891 LWLockRelease(lock);
1892 }
1893
1894 /*
1895 * And the same for members.
1896 *
1897 * (Re-)Initialize our idea of the latest page number for members.
1898 */
1899 pageno = MXOffsetToMemberPage(offset);
1900 pg_atomic_write_u64(&MultiXactMemberCtl->shared->latest_page_number,
1901 pageno);
1902
1903 /*
1904 * Zero out the remainder of the current members page. See notes in
1905 * TrimCLOG() for motivation.
1906 */
1908 if (flagsoff != 0)
1909 {
1910 int slotno;
1912 int memberoff;
1914
1917 slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset);
1918 xidptr = (TransactionId *)
1919 (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
1920
1922
1923 /*
1924 * Note: we don't need to zero out the flag bits in the remaining
1925 * members of the current group, because they are always reset before
1926 * writing.
1927 */
1928
1929 MultiXactMemberCtl->shared->page_dirty[slotno] = true;
1930 LWLockRelease(lock);
1931 }
1932
1933 /* signal that we're officially up */
1937
1938 /* Now compute how far away the next multixid wraparound is. */
1940}

References fb(), MultiXactStateData::finishedStartup, FirstMultiXactId, 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 2599 of file multixact.c.

2600{
2601 MultiXactId oldestMulti;
2602 MultiXactId nextMulti;
2604 MultiXactOffset nextOffset;
2605
2609
2610 /*
2611 * We can only allow one truncation to happen at once. Otherwise parts of
2612 * members might vanish while we're doing lookups or similar. There's no
2613 * need to have an interlock with creating new multis or such, since those
2614 * are constrained by the limits (which only grow, never shrink).
2615 */
2617
2619 nextMulti = MultiXactState->nextMXact;
2620 nextOffset = MultiXactState->nextOffset;
2621 oldestMulti = MultiXactState->oldestMultiXactId;
2623
2624 /*
2625 * Make sure to only attempt truncation if there's values to truncate
2626 * away. In normal processing values shouldn't go backwards, but there's
2627 * some corner cases (due to bugs) where that's possible.
2628 */
2630 {
2632 return;
2633 }
2634
2635 /*
2636 * Compute up to where to truncate MultiXactMember. Lookup the
2637 * corresponding member offset for newOldestMulti for that.
2638 */
2639 if (newOldestMulti == nextMulti)
2640 {
2641 /* there are NO MultiXacts */
2642 newOldestOffset = nextOffset;
2643 }
2645 {
2646 ereport(LOG,
2647 (errmsg("cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
2648 newOldestMulti)));
2650 return;
2651 }
2652
2653 /*
2654 * On crash, MultiXactIdCreateFromMembers() can leave behind multixids
2655 * that were not yet written out and hence have zero offset on disk. If
2656 * such a multixid becomes oldestMulti, we won't be able to look up its
2657 * offset. That should be rare, so we don't try to do anything smart about
2658 * it. Just skip the truncation, and hope that by the next truncation
2659 * attempt, oldestMulti has advanced to a valid multixid.
2660 */
2661 if (newOldestOffset == 0)
2662 {
2663 ereport(LOG,
2664 (errmsg("cannot truncate up to MultiXact %u because it has invalid offset, skipping truncation",
2665 newOldestMulti)));
2667 return;
2668 }
2669
2670 elog(DEBUG1, "performing multixact truncation: "
2671 "oldestMulti %u (offsets segment %" PRIx64 "), "
2672 "oldestOffset %" PRIu64 " (members segment %" PRIx64 ")",
2677
2678 /*
2679 * Do truncation, and the WAL logging of the truncation, in a critical
2680 * section. That way offsets/members cannot get out of sync anymore, i.e.
2681 * once consistent the newOldestMulti will always exist in members, even
2682 * if we crashed in the wrong moment.
2683 */
2685
2686 /*
2687 * Prevent checkpoints from being scheduled concurrently. This is critical
2688 * because otherwise a truncation record might not be replayed after a
2689 * crash/basebackup, even though the state of the data directory would
2690 * require it.
2691 */
2694
2695 /* WAL log truncation */
2697
2698 /*
2699 * Update in-memory limits before performing the truncation, while inside
2700 * the critical section: Have to do it before truncation, to prevent
2701 * concurrent lookups of those values. Has to be inside the critical
2702 * section as otherwise a future call to this function would error out,
2703 * while looking up the oldest member in offsets, if our caller crashes
2704 * before updating the limits.
2705 */
2711
2712 /* First truncate members */
2714
2715 /* Then offsets */
2717
2719
2722}
static void WriteMTruncateXlogRec(Oid oldestMultiDB, MultiXactId endTruncOff, MultiXactOffset endTruncMemb)
Definition multixact.c:2794
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
Definition multixact.c:2779
#define DELAY_CHKPT_START
Definition proc.h:135
PGPROC * MyProc
Definition proc.c:67
int delayChkptFlags
Definition proc.h:263

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 2794 of file multixact.c.

2797{
2800
2801 xlrec.oldestMultiDB = oldestMultiDB;
2802 xlrec.oldestMulti = oldestMulti;
2803 xlrec.oldestOffset = oldestOffset;
2804
2809}
void XLogFlush(XLogRecPtr record)
Definition xlog.c:2784
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

◆ MultiXactMemberCtlData

SlruCtlData MultiXactMemberCtlData
static

Definition at line 117 of file multixact.c.

◆ MultiXactOffsetCtlData

SlruCtlData MultiXactOffsetCtlData
static

Definition at line 116 of file multixact.c.

◆ MultiXactState

◆ MXactCache

◆ MXactContext

MemoryContext MXactContext = NULL
static

Definition at line 248 of file multixact.c.

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

◆ OldestMemberMXactId

◆ OldestVisibleMXactId