PostgreSQL Source Code git master
multixact.h File Reference
#include "access/transam.h"
#include "access/xlogreader.h"
#include "lib/stringinfo.h"
#include "storage/sync.h"
Include dependency graph for multixact.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  MultiXactMember
 
struct  xl_multixact_create
 
struct  xl_multixact_truncate
 

Macros

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

Typedefs

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

Enumerations

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

Functions

MultiXactId MultiXactIdCreate (TransactionId xid1, MultiXactStatus status1, TransactionId xid2, MultiXactStatus status2)
 
MultiXactId MultiXactIdExpand (MultiXactId multi, TransactionId xid, MultiXactStatus status)
 
MultiXactId MultiXactIdCreateFromMembers (int nmembers, MultiXactMember *members)
 
MultiXactId ReadNextMultiXactId (void)
 
void ReadMultiXactIdRange (MultiXactId *oldest, MultiXactId *next)
 
bool MultiXactIdIsRunning (MultiXactId multi, bool isLockOnly)
 
void MultiXactIdSetOldestMember (void)
 
int GetMultiXactIdMembers (MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool isLockOnly)
 
void GetMultiXactInfo (uint32 *multixacts, MultiXactOffset *members, MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset)
 
bool MultiXactIdPrecedes (MultiXactId multi1, MultiXactId multi2)
 
bool MultiXactIdPrecedesOrEquals (MultiXactId multi1, MultiXactId multi2)
 
int multixactoffsetssyncfiletag (const FileTag *ftag, char *path)
 
int multixactmemberssyncfiletag (const FileTag *ftag, char *path)
 
void AtEOXact_MultiXact (void)
 
void AtPrepare_MultiXact (void)
 
void PostPrepare_MultiXact (FullTransactionId fxid)
 
Size MultiXactShmemSize (void)
 
void MultiXactShmemInit (void)
 
void BootStrapMultiXact (void)
 
void StartupMultiXact (void)
 
void TrimMultiXact (void)
 
void SetMultiXactIdLimit (MultiXactId oldest_datminmxid, Oid oldest_datoid)
 
void MultiXactGetCheckptMulti (bool is_shutdown, MultiXactId *nextMulti, MultiXactOffset *nextMultiOffset, MultiXactId *oldestMulti, Oid *oldestMultiDB)
 
void CheckPointMultiXact (void)
 
MultiXactId GetOldestMultiXactId (void)
 
void TruncateMultiXact (MultiXactId newOldestMulti, Oid newOldestMultiDB)
 
void MultiXactSetNextMXact (MultiXactId nextMulti, MultiXactOffset nextMultiOffset)
 
void MultiXactAdvanceNextMXact (MultiXactId minMulti, MultiXactOffset minMultiOffset)
 
void MultiXactAdvanceOldest (MultiXactId oldestMulti, Oid oldestMultiDB)
 
int MultiXactMemberFreezeThreshold (void)
 
void multixact_twophase_recover (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)
 
void multixact_redo (XLogReaderState *record)
 
void multixact_desc (StringInfo buf, XLogReaderState *record)
 
const char * multixact_identify (uint8 info)
 
char * mxid_to_string (MultiXactId multi, int nmembers, MultiXactMember *members)
 
char * mxstatus_to_string (MultiXactStatus status)
 

Macro Definition Documentation

◆ FirstMultiXactId

#define FirstMultiXactId   ((MultiXactId) 1)

Definition at line 26 of file multixact.h.

◆ InvalidMultiXactId

#define InvalidMultiXactId   ((MultiXactId) 0)

Definition at line 25 of file multixact.h.

◆ ISUPDATE_from_mxstatus

#define ISUPDATE_from_mxstatus (   status)     ((status) > MultiXactStatusForUpdate)

Definition at line 51 of file multixact.h.

◆ MaxMultiXactId

#define MaxMultiXactId   ((MultiXactId) 0xFFFFFFFF)

Definition at line 27 of file multixact.h.

◆ MaxMultiXactStatus

#define MaxMultiXactStatus   MultiXactStatusUpdate

Definition at line 48 of file multixact.h.

◆ MultiXactIdIsValid

#define MultiXactIdIsValid (   multi)    ((multi) != InvalidMultiXactId)

Definition at line 29 of file multixact.h.

◆ SizeOfMultiXactCreate

#define SizeOfMultiXactCreate   (offsetof(xl_multixact_create, members))

Definition at line 80 of file multixact.h.

◆ SizeOfMultiXactTruncate

#define SizeOfMultiXactTruncate   (sizeof(xl_multixact_truncate))

Definition at line 95 of file multixact.h.

◆ XLOG_MULTIXACT_CREATE_ID

#define XLOG_MULTIXACT_CREATE_ID   0x20

Definition at line 69 of file multixact.h.

◆ XLOG_MULTIXACT_TRUNCATE_ID

#define XLOG_MULTIXACT_TRUNCATE_ID   0x30

Definition at line 70 of file multixact.h.

◆ XLOG_MULTIXACT_ZERO_MEM_PAGE

#define XLOG_MULTIXACT_ZERO_MEM_PAGE   0x10

Definition at line 68 of file multixact.h.

◆ XLOG_MULTIXACT_ZERO_OFF_PAGE

#define XLOG_MULTIXACT_ZERO_OFF_PAGE   0x00

Definition at line 67 of file multixact.h.

Typedef Documentation

◆ MultiXactMember

◆ xl_multixact_create

◆ xl_multixact_truncate

Enumeration Type Documentation

◆ MultiXactStatus

Enumerator
MultiXactStatusForKeyShare 
MultiXactStatusForShare 
MultiXactStatusForNoKeyUpdate 
MultiXactStatusForUpdate 
MultiXactStatusNoKeyUpdate 
MultiXactStatusUpdate 

Definition at line 36 of file multixact.h.

37{
42 /* an update that doesn't touch "key" columns */
44 /* other updates, and delete */
MultiXactStatus
Definition: multixact.h:37
@ 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

Function Documentation

◆ AtEOXact_MultiXact()

void AtEOXact_MultiXact ( void  )

Definition at line 1565 of file multixact.c.

1566{
1567 /*
1568 * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of
1569 * which should only be valid while within a transaction.
1570 *
1571 * We assume that storing a MultiXactId is atomic and so we need not take
1572 * MultiXactGenLock to do this.
1573 */
1576
1577 /*
1578 * Discard the local MultiXactId cache. Since MXactContext was created as
1579 * a child of TopTransactionContext, we needn't delete it explicitly.
1580 */
1581 MXactContext = NULL;
1583}
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(), InvalidMultiXactId, MXactCache, MXactContext, MyProcNumber, OldestMemberMXactId, and OldestVisibleMXactId.

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

◆ AtPrepare_MultiXact()

void AtPrepare_MultiXact ( void  )

Definition at line 1593 of file multixact.c.

1594{
1596
1597 if (MultiXactIdIsValid(myOldestMember))
1599 &myOldestMember, sizeof(MultiXactId));
1600}
TransactionId MultiXactId
Definition: c.h:681
#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
Definition: twophase_rmgr.h:29

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

Referenced by PrepareTransaction().

◆ BootStrapMultiXact()

void BootStrapMultiXact ( void  )

Definition at line 1790 of file multixact.c.

1791{
1792 /* Zero the initial pages and flush them to disk */
1795}
#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().

◆ CheckPointMultiXact()

void CheckPointMultiXact ( void  )

Definition at line 1965 of file multixact.c.

1966{
1967 TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true);
1968
1969 /*
1970 * Write dirty MultiXact pages to disk. This may result in sync requests
1971 * queued for later handling by ProcessSyncRequests(), as part of the
1972 * checkpoint.
1973 */
1976
1977 TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true);
1978}
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
Definition: slru.c:1347

References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruWriteAll().

Referenced by CheckPointGuts().

◆ GetMultiXactIdMembers()

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

Definition at line 1115 of file multixact.c.

1117{
1118 int64 pageno;
1119 int64 prev_pageno;
1120 int entryno;
1121 int slotno;
1122 MultiXactOffset *offptr;
1123 MultiXactOffset offset;
1124 MultiXactOffset nextMXOffset;
1125 int length;
1126 MultiXactId oldestMXact;
1127 MultiXactId nextMXact;
1128 MultiXactMember *ptr;
1129 LWLock *lock;
1130
1131 debug_elog3(DEBUG2, "GetMembers: asked for %u", multi);
1132
1133 if (!MultiXactIdIsValid(multi) || from_pgupgrade)
1134 {
1135 *members = NULL;
1136 return -1;
1137 }
1138
1139 /* See if the MultiXactId is in the local cache */
1140 length = mXactCacheGetById(multi, members);
1141 if (length >= 0)
1142 {
1143 debug_elog3(DEBUG2, "GetMembers: found %s in the cache",
1144 mxid_to_string(multi, length, *members));
1145 return length;
1146 }
1147
1148 /* Set our OldestVisibleMXactId[] entry if we didn't already */
1150
1151 /*
1152 * If we know the multi is used only for locking and not for updates, then
1153 * we can skip checking if the value is older than our oldest visible
1154 * multi. It cannot possibly still be running.
1155 */
1156 if (isLockOnly &&
1158 {
1159 debug_elog2(DEBUG2, "GetMembers: a locker-only multi is too old");
1160 *members = NULL;
1161 return -1;
1162 }
1163
1164 /*
1165 * We check known limits on MultiXact before resorting to the SLRU area.
1166 *
1167 * An ID older than MultiXactState->oldestMultiXactId cannot possibly be
1168 * useful; it has already been removed, or will be removed shortly, by
1169 * truncation. If one is passed, an error is raised.
1170 *
1171 * Also, an ID >= nextMXact shouldn't ever be seen here; if it is seen, it
1172 * implies undetected ID wraparound has occurred. This raises a hard
1173 * error.
1174 *
1175 * Shared lock is enough here since we aren't modifying any global state.
1176 * Acquire it just long enough to grab the current counter values.
1177 */
1178 LWLockAcquire(MultiXactGenLock, LW_SHARED);
1179
1180 oldestMXact = MultiXactState->oldestMultiXactId;
1181 nextMXact = MultiXactState->nextMXact;
1182
1183 LWLockRelease(MultiXactGenLock);
1184
1185 if (MultiXactIdPrecedes(multi, oldestMXact))
1186 ereport(ERROR,
1187 (errcode(ERRCODE_INTERNAL_ERROR),
1188 errmsg("MultiXactId %u does no longer exist -- apparent wraparound",
1189 multi)));
1190
1191 if (!MultiXactIdPrecedes(multi, nextMXact))
1192 ereport(ERROR,
1193 (errcode(ERRCODE_INTERNAL_ERROR),
1194 errmsg("MultiXactId %u has not been created yet -- apparent wraparound",
1195 multi)));
1196
1197 /*
1198 * Find out the offset at which we need to start reading MultiXactMembers
1199 * and the number of members in the multixact. We determine the latter as
1200 * the difference between this multixact's starting offset and the next
1201 * one's.
1202 */
1203 pageno = MultiXactIdToOffsetPage(multi);
1204 entryno = MultiXactIdToOffsetEntry(multi);
1205
1206 /* Acquire the bank lock for the page we need. */
1209
1210 /* read this multi's offset */
1211 slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi);
1212 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1213 offptr += entryno;
1214 offset = *offptr;
1215
1216 if (offset == 0)
1217 ereport(ERROR,
1219 errmsg("MultiXact %u has invalid offset", multi)));
1220
1221 /* read next multi's offset */
1222 {
1223 MultiXactId tmpMXact;
1224
1225 /* handle wraparound if needed */
1226 tmpMXact = NextMultiXactId(multi);
1227
1228 prev_pageno = pageno;
1229
1230 pageno = MultiXactIdToOffsetPage(tmpMXact);
1231 entryno = MultiXactIdToOffsetEntry(tmpMXact);
1232
1233 if (pageno != prev_pageno)
1234 {
1235 LWLock *newlock;
1236
1237 /*
1238 * Since we're going to access a different SLRU page, if this page
1239 * falls under a different bank, release the old bank's lock and
1240 * acquire the lock of the new bank.
1241 */
1242 newlock = SimpleLruGetBankLock(MultiXactOffsetCtl, pageno);
1243 if (newlock != lock)
1244 {
1245 LWLockRelease(lock);
1246 LWLockAcquire(newlock, LW_EXCLUSIVE);
1247 lock = newlock;
1248 }
1249 slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact);
1250 }
1251
1252 offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno];
1253 offptr += entryno;
1254 nextMXOffset = *offptr;
1255 }
1256
1257 LWLockRelease(lock);
1258 lock = NULL;
1259
1260 /* Sanity check the next offset */
1261 if (nextMXOffset == 0)
1262 ereport(ERROR,
1264 errmsg("MultiXact %u has invalid next offset", multi)));
1265 if (nextMXOffset < offset)
1266 ereport(ERROR,
1268 errmsg("MultiXact %u has offset (%" PRIu64 ") greater than its next offset (%" PRIu64 ")",
1269 multi, offset, nextMXOffset)));
1270 if (nextMXOffset - offset > INT32_MAX)
1271 ereport(ERROR,
1273 errmsg("MultiXact %u has too many members (%" PRIu64 ")",
1274 multi, nextMXOffset - offset)));
1275 length = nextMXOffset - offset;
1276
1277 /* read the members */
1278 ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember));
1279 prev_pageno = -1;
1280 for (int i = 0; i < length; i++, offset++)
1281 {
1282 TransactionId *xactptr;
1283 uint32 *flagsptr;
1284 int flagsoff;
1285 int bshift;
1286 int memberoff;
1287
1288 pageno = MXOffsetToMemberPage(offset);
1289 memberoff = MXOffsetToMemberOffset(offset);
1290
1291 if (pageno != prev_pageno)
1292 {
1293 LWLock *newlock;
1294
1295 /*
1296 * Since we're going to access a different SLRU page, if this page
1297 * falls under a different bank, release the old bank's lock and
1298 * acquire the lock of the new bank.
1299 */
1300 newlock = SimpleLruGetBankLock(MultiXactMemberCtl, pageno);
1301 if (newlock != lock)
1302 {
1303 if (lock)
1304 LWLockRelease(lock);
1305 LWLockAcquire(newlock, LW_EXCLUSIVE);
1306 lock = newlock;
1307 }
1308
1309 slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi);
1310 prev_pageno = pageno;
1311 }
1312
1313 xactptr = (TransactionId *)
1314 (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff);
1315 Assert(TransactionIdIsValid(*xactptr));
1316
1317 flagsoff = MXOffsetToFlagsOffset(offset);
1318 bshift = MXOffsetToFlagsBitShift(offset);
1319 flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff);
1320
1321 ptr[i].xid = *xactptr;
1322 ptr[i].status = (*flagsptr >> bshift) & MXACT_MEMBER_XACT_BITMASK;
1323 }
1324
1325 LWLockRelease(lock);
1326
1327 /*
1328 * Copy the result into the local cache.
1329 */
1330 mXactCachePut(multi, length, ptr);
1331
1332 debug_elog3(DEBUG2, "GetMembers: no cache for %s",
1333 mxid_to_string(multi, length, ptr));
1334 *members = ptr;
1335 return length;
1336}
int64_t int64
Definition: c.h:549
uint64 MultiXactOffset
Definition: c.h:683
uint32_t uint32
Definition: c.h:552
uint32 TransactionId
Definition: c.h:671
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
Assert(PointerIsAligned(start, uint64))
int i
Definition: isn.c:77
if(TABLE==NULL||TABLE_index==NULL)
Definition: isn.c:81
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
Definition: lwlock.c:1174
void LWLockRelease(LWLock *lock)
Definition: lwlock.c:1894
@ LW_SHARED
Definition: lwlock.h:113
@ LW_EXCLUSIVE
Definition: lwlock.h:112
void * palloc(Size size)
Definition: mcxt.c:1365
static int mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
Definition: multixact.c:1419
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:2828
static void MultiXactIdSetOldestVisible(void)
Definition: multixact.c:589
static void mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
Definition: multixact.c:1466
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:1534
static MultiXactStateData * MultiXactState
Definition: multixact.c:216
#define debug_elog2(a, b)
Definition: multixact.c:257
static int MXOffsetToFlagsBitShift(MultiXactOffset32 offset)
#define MXACT_MEMBER_XACT_BITMASK
static int64 MXOffsetToMemberPage(MultiXactOffset32 offset)
static int MXOffsetToMemberOffset(MultiXactOffset32 offset)
static int MultiXactIdToOffsetEntry(MultiXactId multi)
static int64 MultiXactIdToOffsetPage(MultiXactId multi)
static int MXOffsetToFlagsOffset(MultiXactOffset32 offset)
#define ERRCODE_DATA_CORRUPTED
Definition: pg_basebackup.c:42
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
Definition: slru.c:527
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
Definition: slru.h:160
Definition: lwlock.h:42
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, i, if(), 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 members,
MultiXactId oldestMultiXactId,
MultiXactOffset oldestOffset 
)

Definition at line 2464 of file multixact.c.

2466{
2467 MultiXactOffset nextOffset;
2468 MultiXactId nextMultiXactId;
2469
2470 LWLockAcquire(MultiXactGenLock, LW_SHARED);
2471 nextOffset = MultiXactState->nextOffset;
2472 *oldestMultiXactId = MultiXactState->oldestMultiXactId;
2473 nextMultiXactId = MultiXactState->nextMXact;
2474 *oldestOffset = MultiXactState->oldestOffset;
2475 LWLockRelease(MultiXactGenLock);
2476
2477 *members = nextOffset - *oldestOffset;
2478 *multixacts = nextMultiXactId - *oldestMultiXactId;
2479}
MultiXactOffset nextOffset
Definition: multixact.c:135
MultiXactOffset oldestOffset
Definition: multixact.c:152

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

Referenced by MultiXactMemberFreezeThreshold().

◆ GetOldestMultiXactId()

MultiXactId GetOldestMultiXactId ( void  )

Definition at line 2300 of file multixact.c.

2301{
2302 MultiXactId oldestMXact;
2303 int i;
2304
2305 /*
2306 * This is the oldest valid value among all the OldestMemberMXactId[] and
2307 * OldestVisibleMXactId[] entries, or nextMXact if none are valid.
2308 */
2309 LWLockAcquire(MultiXactGenLock, LW_SHARED);
2310 oldestMXact = MultiXactState->nextMXact;
2311 for (i = 0; i < MaxOldestSlot; i++)
2312 {
2313 MultiXactId thisoldest;
2314
2315 thisoldest = OldestMemberMXactId[i];
2316 if (MultiXactIdIsValid(thisoldest) &&
2317 MultiXactIdPrecedes(thisoldest, oldestMXact))
2318 oldestMXact = thisoldest;
2319 thisoldest = OldestVisibleMXactId[i];
2320 if (MultiXactIdIsValid(thisoldest) &&
2321 MultiXactIdPrecedes(thisoldest, oldestMXact))
2322 oldestMXact = thisoldest;
2323 }
2324
2325 LWLockRelease(MultiXactGenLock);
2326
2327 return oldestMXact;
2328}
#define MaxOldestSlot
Definition: multixact.c:213

References 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_desc()

void multixact_desc ( StringInfo  buf,
XLogReaderState record 
)

Definition at line 50 of file mxactdesc.c.

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

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

◆ multixact_identify()

const char * multixact_identify ( uint8  info)

Definition at line 84 of file mxactdesc.c.

85{
86 const char *id = NULL;
87
88 switch (info & ~XLR_INFO_MASK)
89 {
91 id = "ZERO_OFF_PAGE";
92 break;
94 id = "ZERO_MEM_PAGE";
95 break;
97 id = "CREATE_ID";
98 break;
100 id = "TRUNCATE_ID";
101 break;
102 }
103
104 return id;
105}
#define XLR_INFO_MASK
Definition: xlogrecord.h:62

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

◆ multixact_redo()

void multixact_redo ( XLogReaderState record)

Definition at line 2882 of file multixact.c.

2883{
2884 uint8 info = XLogRecGetInfo(record) & ~XLR_INFO_MASK;
2885
2886 /* Backup blocks are not used in multixact records */
2888
2889 if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE)
2890 {
2891 int64 pageno;
2892
2893 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
2895 }
2896 else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE)
2897 {
2898 int64 pageno;
2899
2900 memcpy(&pageno, XLogRecGetData(record), sizeof(pageno));
2902 }
2903 else if (info == XLOG_MULTIXACT_CREATE_ID)
2904 {
2905 xl_multixact_create *xlrec =
2907 TransactionId max_xid;
2908 int i;
2909
2910 /* Store the data back into the SLRU files */
2911 RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers,
2912 xlrec->members);
2913
2914 /* Make sure nextMXact/nextOffset are beyond what this record has */
2916 xlrec->moff + xlrec->nmembers);
2917
2918 /*
2919 * Make sure nextXid is beyond any XID mentioned in the record. This
2920 * should be unnecessary, since any XID found here ought to have other
2921 * evidence in the XLOG, but let's be safe.
2922 */
2923 max_xid = XLogRecGetXid(record);
2924 for (i = 0; i < xlrec->nmembers; i++)
2925 {
2926 if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid))
2927 max_xid = xlrec->members[i].xid;
2928 }
2929
2931 }
2932 else if (info == XLOG_MULTIXACT_TRUNCATE_ID)
2933 {
2935 int64 pageno;
2936
2937 memcpy(&xlrec, XLogRecGetData(record),
2939
2940 elog(DEBUG1, "replaying multixact truncation: "
2941 "offsets [%u, %u), offsets segments [%" PRIx64 ", %" PRIx64 "), "
2942 "members [%" PRIu64 ", %" PRIu64 "), members segments [%" PRIx64 ", %" PRIx64 ")",
2943 xlrec.startTruncOff, xlrec.endTruncOff,
2946 xlrec.startTruncMemb, xlrec.endTruncMemb,
2949
2950 /* should not be required, but more than cheap enough */
2951 LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
2952
2953 /*
2954 * Advance the horizon values, so they're current at the end of
2955 * recovery.
2956 */
2958
2960
2961 /*
2962 * During XLOG replay, latest_page_number isn't necessarily set up
2963 * yet; insert a suitable value to bypass the sanity test in
2964 * SimpleLruTruncate.
2965 */
2966 pageno = MultiXactIdToOffsetPage(xlrec.endTruncOff);
2967 pg_atomic_write_u64(&MultiXactOffsetCtl->shared->latest_page_number,
2968 pageno);
2970
2971 LWLockRelease(MultiXactTruncationLock);
2972 }
2973 else
2974 elog(PANIC, "multixact_redo: unknown op code %u", info);
2975}
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
Definition: atomics.h:485
#define PANIC
Definition: elog.h:42
#define DEBUG1
Definition: elog.h:30
#define elog(elevel,...)
Definition: elog.h:226
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
Definition: multixact.c:2594
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
Definition: multixact.c:2584
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
Definition: multixact.c:759
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
Definition: multixact.c:2161
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
Definition: multixact.c:2011
#define SizeOfMultiXactTruncate
Definition: multixact.h:95
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 XLogRecGetXid(decoder)
Definition: xlogreader.h:411
#define XLogRecHasAnyBlockRefs(decoder)
Definition: xlogreader.h:416

References AdvanceNextFullTransactionIdPastXid(), Assert(), DEBUG1, elog, xl_multixact_truncate::endTruncMemb, xl_multixact_truncate::endTruncOff, i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), xl_multixact_create::members, xl_multixact_create::mid, xl_multixact_create::moff, MultiXactAdvanceNextMXact(), MultiXactIdToOffsetPage(), MultiXactIdToOffsetSegment(), MultiXactMemberCtl, MultiXactOffsetCtl, MXOffsetToMemberSegment(), NextMultiXactId(), xl_multixact_create::nmembers, xl_multixact_truncate::oldestMultiDB, PANIC, PerformMembersTruncation(), PerformOffsetsTruncation(), pg_atomic_write_u64(), RecordNewMultiXact(), SetMultiXactIdLimit(), SimpleLruZeroAndWritePage(), SizeOfMultiXactTruncate, xl_multixact_truncate::startTruncMemb, xl_multixact_truncate::startTruncOff, TransactionIdPrecedes(), MultiXactMember::xid, 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 1692 of file multixact.c.

1694{
1695 multixact_twophase_postcommit(fxid, info, recdata, len);
1696}
void multixact_twophase_postcommit(FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
Definition: multixact.c:1677
const void size_t len

References len, and multixact_twophase_postcommit().

◆ multixact_twophase_postcommit()

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

Definition at line 1677 of file multixact.c.

1679{
1680 ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, true);
1681
1682 Assert(len == sizeof(MultiXactId));
1683
1684 OldestMemberMXactId[dummyProcNumber] = InvalidMultiXactId;
1685}
int ProcNumber
Definition: procnumber.h:24
ProcNumber TwoPhaseGetDummyProcNumber(FullTransactionId fxid, bool lock_held)
Definition: twophase.c:908

References Assert(), 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 1656 of file multixact.c.

1658{
1659 ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, false);
1660 MultiXactId oldestMember;
1661
1662 /*
1663 * Get the oldest member XID from the state file record, and set it in the
1664 * OldestMemberMXactId slot reserved for this prepared transaction.
1665 */
1666 Assert(len == sizeof(MultiXactId));
1667 oldestMember = *((MultiXactId *) recdata);
1668
1669 OldestMemberMXactId[dummyProcNumber] = oldestMember;
1670}

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

◆ MultiXactAdvanceNextMXact()

void MultiXactAdvanceNextMXact ( MultiXactId  minMulti,
MultiXactOffset  minMultiOffset 
)

Definition at line 2161 of file multixact.c.

2163{
2164 Assert(MultiXactIdIsValid(minMulti));
2165
2166 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2168 {
2169 debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti);
2170 MultiXactState->nextMXact = minMulti;
2171 }
2172 if (MultiXactState->nextOffset < minMultiOffset)
2173 {
2174 debug_elog3(DEBUG2, "MultiXact: setting next offset to %" PRIu64,
2175 minMultiOffset);
2176 MultiXactState->nextOffset = minMultiOffset;
2177 }
2178 LWLockRelease(MultiXactGenLock);
2179}

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

Referenced by multixact_redo(), and xlog_redo().

◆ MultiXactAdvanceOldest()

void MultiXactAdvanceOldest ( MultiXactId  oldestMulti,
Oid  oldestMultiDB 
)

Definition at line 2188 of file multixact.c.

2189{
2191
2193 SetMultiXactIdLimit(oldestMulti, oldestMultiDB);
2194}
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 1943 of file multixact.c.

1948{
1949 LWLockAcquire(MultiXactGenLock, LW_SHARED);
1950 *nextMulti = MultiXactState->nextMXact;
1951 *nextMultiOffset = MultiXactState->nextOffset;
1952 *oldestMulti = MultiXactState->oldestMultiXactId;
1953 *oldestMultiDB = MultiXactState->oldestMultiXactDB;
1954 LWLockRelease(MultiXactGenLock);
1955
1957 "MultiXact: checkpoint is nextMulti %u, nextOffset %" PRIu64 ", oldestMulti %u in DB %u",
1958 *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
1959}
#define debug_elog6(a, b, c, d, e, f)
Definition: multixact.c:261

References DEBUG2, debug_elog6, 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 301 of file multixact.c.

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

References Assert(), DEBUG2, debug_elog3, 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 658 of file multixact.c.

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

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

References Assert(), DEBUG2, debug_elog3, debug_elog4, debug_elog5, 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 465 of file multixact.c.

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

References DEBUG2, debug_elog2, debug_elog3, debug_elog4, 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 2842 of file multixact.c.

2843{
2844 int32 diff = (int32) (multi1 - multi2);
2845
2846 return (diff <= 0);
2847}

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

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

References DEBUG2, debug_elog4, 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().

◆ MultiXactMemberFreezeThreshold()

int MultiXactMemberFreezeThreshold ( void  )

Definition at line 2510 of file multixact.c.

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

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

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

◆ multixactmemberssyncfiletag()

int multixactmemberssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 2990 of file multixact.c.

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

References MultiXactMemberCtl, and SlruSyncFileTag().

◆ multixactoffsetssyncfiletag()

int multixactoffsetssyncfiletag ( const FileTag ftag,
char *  path 
)

Definition at line 2981 of file multixact.c.

2982{
2983 return SlruSyncFileTag(MultiXactOffsetCtl, ftag, path);
2984}

References MultiXactOffsetCtl, and SlruSyncFileTag().

◆ MultiXactSetNextMXact()

void MultiXactSetNextMXact ( MultiXactId  nextMulti,
MultiXactOffset  nextMultiOffset 
)

Definition at line 1989 of file multixact.c.

1991{
1992 Assert(MultiXactIdIsValid(nextMulti));
1993 debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %" PRIu64,
1994 nextMulti, nextMultiOffset);
1995
1996 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1997 MultiXactState->nextMXact = nextMulti;
1998 MultiXactState->nextOffset = nextMultiOffset;
1999 LWLockRelease(MultiXactGenLock);
2000}

References Assert(), DEBUG2, debug_elog4, 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 1721 of file multixact.c.

1722{
1723 bool found;
1724
1725 debug_elog2(DEBUG2, "Shared Memory Init for MultiXact");
1726
1729
1731 "multixact_offset", multixact_offset_buffers, 0,
1732 "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1733 LWTRANCHE_MULTIXACTOFFSET_SLRU,
1735 false);
1738 "multixact_member", multixact_member_buffers, 0,
1739 "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1740 LWTRANCHE_MULTIXACTMEMBER_SLRU,
1742 true);
1743 /* doesn't call SimpleLruTruncate() or meet criteria for unit tests */
1744
1745 /* Initialize our shared state struct */
1746 MultiXactState = ShmemInitStruct("Shared MultiXact State",
1748 &found);
1749 if (!IsUnderPostmaster)
1750 {
1751 Assert(!found);
1752
1753 /* Make sure we zero out the per-backend state */
1755 }
1756 else
1757 Assert(found);
1758
1759 /*
1760 * Set up array pointers.
1761 */
1764}
#define MemSet(start, val, len)
Definition: c.h:1032
int multixact_offset_buffers
Definition: globals.c:163
bool IsUnderPostmaster
Definition: globals.c:120
int multixact_member_buffers
Definition: globals.c:162
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:2816
#define SHARED_MULTIXACT_STATE_SIZE
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
Definition: multixact.c:2795
#define MULTIXACT_OFFSETS_PER_PAGE
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, 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 1704 of file multixact.c.

1705{
1706 Size size;
1707
1708 /* We need 2*MaxOldestSlot perBackendXactIds[] entries */
1709#define SHARED_MULTIXACT_STATE_SIZE \
1710 add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1711 mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1712
1716
1717 return size;
1718}
size_t Size
Definition: c.h:624
Size add_size(Size s1, Size s2)
Definition: shmem.c:495
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().

◆ mxid_to_string()

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

Definition at line 1534 of file multixact.c.

1535{
1536 static char *str = NULL;
1538 int i;
1539
1540 if (str != NULL)
1541 pfree(str);
1542
1544
1545 appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid,
1546 mxstatus_to_string(members[0].status));
1547
1548 for (i = 1; i < nmembers; i++)
1549 appendStringInfo(&buf, ", %u (%s)", members[i].xid,
1550 mxstatus_to_string(members[i].status));
1551
1554 pfree(buf.data);
1555 return str;
1556}
const char * str
char * MemoryContextStrdup(MemoryContext context, const char *string)
Definition: mcxt.c:1746
MemoryContext TopMemoryContext
Definition: mcxt.c:166
void appendStringInfoChar(StringInfo str, char ch)
Definition: stringinfo.c:242
void initStringInfo(StringInfo str)
Definition: stringinfo.c:97

References appendStringInfo(), appendStringInfoChar(), buf, 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 1511 of file multixact.c.

1512{
1513 switch (status)
1514 {
1516 return "keysh";
1518 return "sh";
1520 return "fornokeyupd";
1522 return "forupd";
1524 return "nokeyupd";
1526 return "upd";
1527 default:
1528 elog(ERROR, "unrecognized multixact status %d", status);
1529 return "";
1530 }
1531}

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

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

◆ PostPrepare_MultiXact()

void PostPrepare_MultiXact ( FullTransactionId  fxid)

Definition at line 1607 of file multixact.c.

1608{
1609 MultiXactId myOldestMember;
1610
1611 /*
1612 * Transfer our OldestMemberMXactId value to the slot reserved for the
1613 * prepared transaction.
1614 */
1615 myOldestMember = OldestMemberMXactId[MyProcNumber];
1616 if (MultiXactIdIsValid(myOldestMember))
1617 {
1618 ProcNumber dummyProcNumber = TwoPhaseGetDummyProcNumber(fxid, false);
1619
1620 /*
1621 * Even though storing MultiXactId is atomic, acquire lock to make
1622 * sure others see both changes, not just the reset of the slot of the
1623 * current backend. Using a volatile pointer might suffice, but this
1624 * isn't a hot spot.
1625 */
1626 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
1627
1628 OldestMemberMXactId[dummyProcNumber] = myOldestMember;
1630
1631 LWLockRelease(MultiXactGenLock);
1632 }
1633
1634 /*
1635 * We don't need to transfer OldestVisibleMXactId value, because the
1636 * transaction is not going to be looking at any more multixacts once it's
1637 * prepared.
1638 *
1639 * We assume that storing a MultiXactId is atomic and so we need not take
1640 * MultiXactGenLock to do this.
1641 */
1643
1644 /*
1645 * Discard the local MultiXactId cache like in AtEOXact_MultiXact.
1646 */
1647 MXactContext = NULL;
1649}

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

Referenced by PrepareTransaction().

◆ ReadMultiXactIdRange()

void ReadMultiXactIdRange ( MultiXactId oldest,
MultiXactId next 
)

Definition at line 639 of file multixact.c.

640{
641 LWLockAcquire(MultiXactGenLock, LW_SHARED);
644 LWLockRelease(MultiXactGenLock);
645}
static int32 next
Definition: blutils.c:224

References LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactState, next, MultiXactStateData::nextMXact, and MultiXactStateData::oldestMultiXactId.

Referenced by update_cached_mxid_range().

◆ ReadNextMultiXactId()

MultiXactId ReadNextMultiXactId ( void  )

Definition at line 622 of file multixact.c.

623{
624 MultiXactId mxid;
625
626 /* XXX we could presumably do this without a lock. */
627 LWLockAcquire(MultiXactGenLock, LW_SHARED);
629 LWLockRelease(MultiXactGenLock);
630
631 return mxid;
632}

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

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

◆ SetMultiXactIdLimit()

void SetMultiXactIdLimit ( MultiXactId  oldest_datminmxid,
Oid  oldest_datoid 
)

Definition at line 2011 of file multixact.c.

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

References Assert(), autovacuum_multixact_freeze_max_age, DEBUG1, ereport, errhint(), errmsg_internal(), errmsg_plural(), MultiXactStateData::finishedStartup, FirstMultiXactId, get_database_name(), InRecovery, IsTransactionState(), IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaxMultiXactId, MultiXactStateData::multiStopLimit, MultiXactStateData::multiVacLimit, MultiXactStateData::multiWarnLimit, MultiXactStateData::multiWrapLimit, MultiXactIdIsValid, MultiXactIdPrecedes(), 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().

◆ StartupMultiXact()

void StartupMultiXact ( void  )

Definition at line 1806 of file multixact.c.

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

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

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

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

2620{
2621 MultiXactId oldestMulti;
2622 MultiXactId nextMulti;
2623 MultiXactOffset newOldestOffset;
2624 MultiXactOffset oldestOffset;
2625 MultiXactOffset nextOffset;
2626 mxtruncinfo trunc;
2627 MultiXactId earliest;
2628
2631 Assert(MultiXactIdIsValid(newOldestMulti));
2632
2633 /*
2634 * We can only allow one truncation to happen at once. Otherwise parts of
2635 * members might vanish while we're doing lookups or similar. There's no
2636 * need to have an interlock with creating new multis or such, since those
2637 * are constrained by the limits (which only grow, never shrink).
2638 */
2639 LWLockAcquire(MultiXactTruncationLock, LW_EXCLUSIVE);
2640
2641 LWLockAcquire(MultiXactGenLock, LW_SHARED);
2642 nextMulti = MultiXactState->nextMXact;
2643 nextOffset = MultiXactState->nextOffset;
2644 oldestMulti = MultiXactState->oldestMultiXactId;
2645 LWLockRelease(MultiXactGenLock);
2646
2647 /*
2648 * Make sure to only attempt truncation if there's values to truncate
2649 * away. In normal processing values shouldn't go backwards, but there's
2650 * some corner cases (due to bugs) where that's possible.
2651 */
2652 if (MultiXactIdPrecedesOrEquals(newOldestMulti, oldestMulti))
2653 {
2654 LWLockRelease(MultiXactTruncationLock);
2655 return;
2656 }
2657
2658 /*
2659 * Note we can't just plow ahead with the truncation; it's possible that
2660 * there are no segments to truncate, which is a problem because we are
2661 * going to attempt to read the offsets page to determine where to
2662 * truncate the members SLRU. So we first scan the directory to determine
2663 * the earliest offsets page number that we can read without error.
2664 *
2665 * When nextMXact is less than one segment away from multiWrapLimit,
2666 * SlruScanDirCbFindEarliest can find some early segment other than the
2667 * actual earliest. (MultiXactOffsetPagePrecedes(EARLIEST, LATEST)
2668 * returns false, because not all pairs of entries have the same answer.)
2669 * That can also arise when an earlier truncation attempt failed unlink()
2670 * or returned early from this function. The only consequence is
2671 * returning early, which wastes space that we could have liberated.
2672 *
2673 * NB: It's also possible that the page that oldestMulti is on has already
2674 * been truncated away, and we crashed before updating oldestMulti.
2675 */
2676 trunc.earliestExistingPage = -1;
2679 if (earliest < FirstMultiXactId)
2680 earliest = FirstMultiXactId;
2681
2682 /* If there's nothing to remove, we can bail out early. */
2683 if (MultiXactIdPrecedes(oldestMulti, earliest))
2684 {
2685 LWLockRelease(MultiXactTruncationLock);
2686 return;
2687 }
2688
2689 /*
2690 * First, compute the safe truncation point for MultiXactMember. This is
2691 * the starting offset of the oldest multixact.
2692 *
2693 * Hopefully, find_multixact_start will always work here, because we've
2694 * already checked that it doesn't precede the earliest MultiXact on disk.
2695 * But if it fails, don't truncate anything, and log a message.
2696 */
2697 if (oldestMulti == nextMulti)
2698 {
2699 /* there are NO MultiXacts */
2700 oldestOffset = nextOffset;
2701 }
2702 else if (!find_multixact_start(oldestMulti, &oldestOffset))
2703 {
2704 ereport(LOG,
2705 (errmsg("oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation",
2706 oldestMulti, earliest)));
2707 LWLockRelease(MultiXactTruncationLock);
2708 return;
2709 }
2710
2711 /*
2712 * Secondly compute up to where to truncate. Lookup the corresponding
2713 * member offset for newOldestMulti for that.
2714 */
2715 if (newOldestMulti == nextMulti)
2716 {
2717 /* there are NO MultiXacts */
2718 newOldestOffset = nextOffset;
2719 }
2720 else if (!find_multixact_start(newOldestMulti, &newOldestOffset))
2721 {
2722 ereport(LOG,
2723 (errmsg("cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
2724 newOldestMulti)));
2725 LWLockRelease(MultiXactTruncationLock);
2726 return;
2727 }
2728
2729 elog(DEBUG1, "performing multixact truncation: "
2730 "offsets [%u, %u), offsets segments [%" PRIx64 ", %" PRIx64 "), "
2731 "members [%" PRIu64 ", %" PRIu64 "), members segments [%" PRIx64 ", %" PRIx64 ")",
2732 oldestMulti, newOldestMulti,
2733 MultiXactIdToOffsetSegment(oldestMulti),
2734 MultiXactIdToOffsetSegment(newOldestMulti),
2735 oldestOffset, newOldestOffset,
2736 MXOffsetToMemberSegment(oldestOffset),
2737 MXOffsetToMemberSegment(newOldestOffset));
2738
2739 /*
2740 * Do truncation, and the WAL logging of the truncation, in a critical
2741 * section. That way offsets/members cannot get out of sync anymore, i.e.
2742 * once consistent the newOldestMulti will always exist in members, even
2743 * if we crashed in the wrong moment.
2744 */
2746
2747 /*
2748 * Prevent checkpoints from being scheduled concurrently. This is critical
2749 * because otherwise a truncation record might not be replayed after a
2750 * crash/basebackup, even though the state of the data directory would
2751 * require it.
2752 */
2755
2756 /* WAL log truncation */
2757 WriteMTruncateXlogRec(newOldestMultiDB,
2758 oldestMulti, newOldestMulti,
2759 oldestOffset, newOldestOffset);
2760
2761 /*
2762 * Update in-memory limits before performing the truncation, while inside
2763 * the critical section: Have to do it before truncation, to prevent
2764 * concurrent lookups of those values. Has to be inside the critical
2765 * section as otherwise a future call to this function would error out,
2766 * while looking up the oldest member in offsets, if our caller crashes
2767 * before updating the limits.
2768 */
2769 LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE);
2770 MultiXactState->oldestMultiXactId = newOldestMulti;
2771 MultiXactState->oldestMultiXactDB = newOldestMultiDB;
2772 MultiXactState->oldestOffset = newOldestOffset;
2773 LWLockRelease(MultiXactGenLock);
2774
2775 /* First truncate members */
2776 PerformMembersTruncation(oldestOffset, newOldestOffset);
2777
2778 /* Then offsets */
2779 PerformOffsetsTruncation(oldestMulti, newOldestMulti);
2780
2781 MyProc->delayChkptFlags &= ~DELAY_CHKPT_START;
2782
2784 LWLockRelease(MultiXactTruncationLock);
2785}
#define LOG
Definition: elog.h:31
#define START_CRIT_SECTION()
Definition: miscadmin.h:150
static void WriteMTruncateXlogRec(Oid oldestMultiDB, MultiXactId startTruncOff, MultiXactId endTruncOff, MultiXactOffset startTruncMemb, MultiXactOffset endTruncMemb)
Definition: multixact.c:2857
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result)
Definition: multixact.c:2421
static bool SlruScanDirCbFindEarliest(SlruCtl ctl, char *filename, int64 segpage, void *data)
Definition: multixact.c:2566
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
Definition: multixact.c:2842
#define DELAY_CHKPT_START
Definition: proc.h:135
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
Definition: slru.c:1816
PGPROC * MyProc
Definition: proc.c:67
int delayChkptFlags
Definition: proc.h:257
int64 earliestExistingPage
Definition: multixact.c:2558
bool RecoveryInProgress(void)
Definition: xlog.c:6404

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

Referenced by vac_truncate_clog().