98#define MULTIXACT_MEMBER_LOW_THRESHOLD UINT64CONST(2000000000)
99#define MULTIXACT_MEMBER_HIGH_THRESHOLD UINT64CONST(4000000000)
119#define MultiXactOffsetCtl (&MultiXactOffsetCtlData)
120#define MultiXactMemberCtl (&MultiXactMemberCtlData)
213#define MaxOldestSlot (MaxBackends + max_prepared_xacts)
246#define MAX_CACHE_ENTRIES 256
250#ifdef MULTIXACT_DEBUG
251#define debug_elog2(a,b) elog(a,b)
252#define debug_elog3(a,b,c) elog(a,b,c)
253#define debug_elog4(a,b,c,d) elog(a,b,c,d)
254#define debug_elog5(a,b,c,d,e) elog(a,b,c,d,e)
255#define debug_elog6(a,b,c,d,e,f) elog(a,b,c,d,e,f)
257#define debug_elog2(a,b)
258#define debug_elog3(a,b,c)
259#define debug_elog4(a,b,c,d)
260#define debug_elog5(a,b,c,d,e)
261#define debug_elog6(a,b,c,d,e,f)
321 members[0].
xid = xid1;
322 members[0].
status = status1;
323 members[1].
xid = xid2;
324 members[1].
status = status2;
403 for (
i = 0;
i < nmembers;
i++)
406 (members[
i].status == status))
430 for (
i = 0,
j = 0;
i < nmembers;
i++)
441 newMembers[
j].
xid = xid;
442 newMembers[
j++].
status = status;
492 for (
i = 0;
i < nmembers;
i++)
507 for (
i = 0;
i < nmembers;
i++)
605 oldestMXact = thisoldest;
687 bool has_update =
false;
689 for (
i = 0;
i < nmembers;
i++)
694 elog(
ERROR,
"new multixact has more than one updating member: %s",
807 if (*offptr != offset)
818 if (next_pageno == pageno)
820 next_offptr = offptr + 1;
834 next_offptr += next_entryno;
838 next_offset = offset + nmembers;
839 if (next_offset == 0)
841 if (*next_offptr != next_offset)
844 Assert(*next_offptr == 0);
845 *next_offptr = next_offset;
854 for (
int i = 0;
i < nmembers;
i++, offset++)
870 if (pageno != prev_pageno)
878 if (lock != prevlock)
880 if (prevlock != NULL)
887 prev_pageno = pageno;
893 *memberptr = members[
i].
xid;
898 flagsval = *flagsptr;
900 flagsval |= (members[
i].
status << bshift);
901 *flagsptr = flagsval;
906 if (prevlock != NULL)
935 elog(
ERROR,
"cannot assign MultiXactIds during recovery");
986 (
errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
987 errmsg(
"database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database \"%s\"",
989 errhint(
"Execute a database-wide VACUUM in that database.\n"
990 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
993 (
errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
994 errmsg(
"database is not accepting commands that assign new MultiXactIds to avoid wraparound data loss in database with OID %u",
996 errhint(
"Execute a database-wide VACUUM in that database.\n"
997 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1015 (
errmsg_plural(
"database \"%s\" must be vacuumed before %u more MultiXactId is used",
1016 "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
1017 multiWrapLimit - result,
1019 multiWrapLimit - result),
1020 errhint(
"Execute a database-wide VACUUM in that database.\n"
1021 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1024 (
errmsg_plural(
"database with OID %u must be vacuumed before %u more MultiXactId is used",
1025 "database with OID %u must be vacuumed before %u more MultiXactIds are used",
1026 multiWrapLimit - result,
1028 multiWrapLimit - result),
1029 errhint(
"Execute a database-wide VACUUM in that database.\n"
1030 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
1056 if (nextOffset + nmembers < nextOffset)
1058 (
errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED),
1059 errmsg(
"MultiXact members would wrap around")));
1060 *offset = nextOffset;
1116 bool from_pgupgrade,
bool isLockOnly)
1187 (
errcode(ERRCODE_INTERNAL_ERROR),
1188 errmsg(
"MultiXactId %u does no longer exist -- apparent wraparound",
1193 (
errcode(ERRCODE_INTERNAL_ERROR),
1194 errmsg(
"MultiXactId %u has not been created yet -- apparent wraparound",
1219 errmsg(
"MultiXact %u has invalid offset", multi)));
1228 prev_pageno = pageno;
1233 if (pageno != prev_pageno)
1243 if (newlock != lock)
1254 nextMXOffset = *offptr;
1261 if (nextMXOffset == 0)
1264 errmsg(
"MultiXact %u has invalid next offset", multi)));
1265 if (nextMXOffset < offset)
1268 errmsg(
"MultiXact %u has offset (%" PRIu64
") greater than its next offset (%" PRIu64
")",
1269 multi, offset, nextMXOffset)));
1270 if (nextMXOffset - offset > INT32_MAX)
1273 errmsg(
"MultiXact %u has too many members (%" PRIu64
")",
1274 multi, nextMXOffset - offset)));
1275 length = nextMXOffset - offset;
1280 for (
int i = 0;
i < length;
i++, offset++)
1291 if (pageno != prev_pageno)
1301 if (newlock != lock)
1310 prev_pageno = pageno;
1321 ptr[
i].
xid = *xactptr;
1351 if (member1.
xid > member2.
xid)
1353 if (member1.
xid < member2.
xid)
1402 return entry->
multi;
1430 if (entry->
multi == multi)
1438 memcpy(ptr, entry->
members, size);
1478 "MultiXact cache context",
1487 entry->
multi = multi;
1520 return "fornokeyupd";
1528 elog(
ERROR,
"unrecognized multixact status %d", status);
1536 static char *
str = NULL;
1548 for (
i = 1;
i < nmembers;
i++)
1709#define SHARED_MULTIXACT_STATE_SIZE \
1710 add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1711 mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1732 "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1733 LWTRANCHE_MULTIXACTOFFSET_SLRU,
1739 "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1740 LWTRANCHE_MULTIXACTMEMBER_SLRU,
1918 MemSet(xidptr, 0, BLCKSZ - memberoff);
1957 "MultiXact: checkpoint is nextMulti %u, nextOffset %" PRIu64
", oldestMulti %u in DB %u",
1958 *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
1967 TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(
true);
1977 TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(
true);
1994 nextMulti, nextMultiOffset);
2034 multiStopLimit = multiWrapLimit - 3000000;
2048 multiWarnLimit = multiWrapLimit - 40000000;
2077 (
errmsg_internal(
"MultiXactId wrap limit is %u, limited by database with OID %u",
2078 multiWrapLimit, oldest_datoid)));
2114 char *oldest_datname;
2128 oldest_datname = NULL;
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,
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.")));
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,
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.")));
2247 while (nmembers > 0)
2258 if (flagsoff == 0 && flagsbit == 0)
2318 oldestMXact = thisoldest;
2322 oldestMXact = thisoldest;
2341 bool oldestOffsetKnown =
false;
2364 if (oldestMultiXactId == nextMXact)
2370 oldestOffset = nextOffset;
2371 oldestOffsetKnown =
true;
2390 if (oldestOffsetKnown)
2396 (
errmsg(
"MultiXact member truncation is disabled because oldest checkpointed MultiXact %u does not exist on disk",
2397 oldestMultiXactId)));
2403 if (oldestOffsetKnown)
2477 *members = nextOffset - *oldestOffset;
2478 *multixacts = nextMultiXactId - *oldestMultiXactId;
2514 uint32 victim_multixacts;
2521 GetMultiXactInfo(&multixacts, &members, &oldestMultiXactId, &oldestOffset);
2543 if (fraction >= 1.0)
2546 victim_multixacts = multixacts * fraction;
2547 result = multixacts - victim_multixacts;
2697 if (oldestMulti == nextMulti)
2700 oldestOffset = nextOffset;
2705 (
errmsg(
"oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation",
2706 oldestMulti, earliest)));
2715 if (newOldestMulti == nextMulti)
2718 newOldestOffset = nextOffset;
2723 (
errmsg(
"cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
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,
2735 oldestOffset, newOldestOffset,
2758 oldestMulti, newOldestMulti,
2759 oldestOffset, newOldestOffset);
2818 return page1 < page2;
2940 elog(
DEBUG1,
"replaying multixact truncation: "
2941 "offsets [%u, %u), offsets segments [%" PRIx64
", %" PRIx64
"), "
2942 "members [%" PRIu64
", %" PRIu64
"), members segments [%" PRIx64
", %" PRIx64
")",
2974 elog(
PANIC,
"multixact_redo: unknown op code %u", info);
static void pg_atomic_write_u64(volatile pg_atomic_uint64 *ptr, uint64 val)
int autovacuum_multixact_freeze_max_age
TransactionId MultiXactId
#define FLEXIBLE_ARRAY_MEMBER
#define MemSet(start, val, len)
int errmsg_plural(const char *fmt_singular, const char *fmt_plural, unsigned long n,...)
int errmsg_internal(const char *fmt,...)
int errhint(const char *fmt,...)
int errcode(int sqlerrcode)
int errmsg(const char *fmt,...)
#define ereport(elevel,...)
#define palloc_array(type, count)
Datum difference(PG_FUNCTION_ARGS)
int multixact_offset_buffers
int multixact_member_buffers
Assert(PointerIsAligned(start, uint64))
#define dclist_container(type, membername, ptr)
static uint32 dclist_count(const dclist_head *head)
static void dclist_move_head(dclist_head *head, dlist_node *node)
static dlist_node * dclist_tail_node(dclist_head *head)
static void dclist_delete_from(dclist_head *head, dlist_node *node)
#define DCLIST_STATIC_INIT(name)
static void dclist_push_head(dclist_head *head, dlist_node *node)
static void dclist_init(dclist_head *head)
#define dclist_foreach(iter, lhead)
#define INJECTION_POINT_CACHED(name, arg)
#define INJECTION_POINT_LOAD(name)
if(TABLE==NULL||TABLE_index==NULL)
char * get_database_name(Oid dbid)
bool LWLockAcquire(LWLock *lock, LWLockMode mode)
void LWLockRelease(LWLock *lock)
char * MemoryContextStrdup(MemoryContext context, const char *string)
void * MemoryContextAlloc(MemoryContext context, Size size)
MemoryContext TopTransactionContext
void pfree(void *pointer)
MemoryContext TopMemoryContext
#define AllocSetContextCreate
#define ALLOCSET_SMALL_SIZES
#define START_CRIT_SECTION()
#define END_CRIT_SECTION()
static void WriteMTruncateXlogRec(Oid oldestMultiDB, MultiXactId startTruncOff, MultiXactId endTruncOff, MultiXactOffset startTruncMemb, MultiXactOffset endTruncMemb)
static MultiXactId PreviousMultiXactId(MultiXactId multi)
static SlruCtlData MultiXactOffsetCtlData
void MultiXactShmemInit(void)
static bool MultiXactMemberPagePrecedes(int64 page1, int64 page2)
static MultiXactId GetNewMultiXactId(int nmembers, MultiXactOffset *offset)
static int mXactCacheGetById(MultiXactId multi, MultiXactMember **members)
MultiXactId MultiXactIdExpand(MultiXactId multi, TransactionId xid, MultiXactStatus status)
static void ExtendMultiXactMember(MultiXactOffset offset, int nmembers)
void ReadMultiXactIdRange(MultiXactId *oldest, MultiXactId *next)
static void PerformOffsetsTruncation(MultiXactId oldestMulti, MultiXactId newOldestMulti)
bool MultiXactIdPrecedes(MultiXactId multi1, MultiXactId multi2)
char * mxstatus_to_string(MultiXactStatus status)
void multixact_redo(XLogReaderState *record)
void multixact_twophase_postcommit(FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
#define debug_elog5(a, b, c, d, e)
static void MultiXactIdSetOldestVisible(void)
int multixactoffsetssyncfiletag(const FileTag *ftag, char *path)
void GetMultiXactInfo(uint32 *multixacts, MultiXactOffset *members, MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset)
static bool find_multixact_start(MultiXactId multi, MultiXactOffset *result)
void PostPrepare_MultiXact(FullTransactionId fxid)
void MultiXactSetNextMXact(MultiXactId nextMulti, MultiXactOffset nextMultiOffset)
#define MultiXactMemberCtl
static bool SlruScanDirCbFindEarliest(SlruCtl ctl, char *filename, int64 segpage, void *data)
void AtPrepare_MultiXact(void)
bool MultiXactIdPrecedesOrEquals(MultiXactId multi1, MultiXactId multi2)
void MultiXactAdvanceOldest(MultiXactId oldestMulti, Oid oldestMultiDB)
static void mXactCachePut(MultiXactId multi, int nmembers, MultiXactMember *members)
bool MultiXactIdIsRunning(MultiXactId multi, bool isLockOnly)
void MultiXactIdSetOldestMember(void)
static void PerformMembersTruncation(MultiXactOffset oldestOffset, MultiXactOffset newOldestOffset)
#define MULTIXACT_MEMBER_LOW_THRESHOLD
static MemoryContext MXactContext
#define SHARED_MULTIXACT_STATE_SIZE
static MultiXactId * OldestVisibleMXactId
struct mxtruncinfo mxtruncinfo
static int mxactMemberComparator(const void *arg1, const void *arg2)
struct MultiXactStateData MultiXactStateData
static void ExtendMultiXactOffset(MultiXactId multi)
Size MultiXactShmemSize(void)
#define MultiXactOffsetCtl
void MultiXactGetCheckptMulti(bool is_shutdown, MultiXactId *nextMulti, MultiXactOffset *nextMultiOffset, MultiXactId *oldestMulti, Oid *oldestMultiDB)
static void RecordNewMultiXact(MultiXactId multi, MultiXactOffset offset, int nmembers, MultiXactMember *members)
int multixactmemberssyncfiletag(const FileTag *ftag, char *path)
#define MAX_CACHE_ENTRIES
static MultiXactId NextMultiXactId(MultiXactId multi)
MultiXactId GetOldestMultiXactId(void)
void CheckPointMultiXact(void)
MultiXactId MultiXactIdCreateFromMembers(int nmembers, MultiXactMember *members)
struct mXactCacheEnt mXactCacheEnt
static MultiXactId mXactCacheGetBySet(int nmembers, MultiXactMember *members)
static dclist_head MXactCache
#define debug_elog3(a, b, c)
char * mxid_to_string(MultiXactId multi, int nmembers, MultiXactMember *members)
#define debug_elog4(a, b, c, d)
void multixact_twophase_postabort(FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
static bool MultiXactOffsetPagePrecedes(int64 page1, int64 page2)
int MultiXactMemberFreezeThreshold(void)
static void SetOldestOffset(void)
void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset)
static MultiXactId * OldestMemberMXactId
static MultiXactStateData * MultiXactState
MultiXactId ReadNextMultiXactId(void)
void BootStrapMultiXact(void)
#define debug_elog6(a, b, c, d, e, f)
void multixact_twophase_recover(FullTransactionId fxid, uint16 info, void *recdata, uint32 len)
MultiXactId MultiXactIdCreate(TransactionId xid1, MultiXactStatus status1, TransactionId xid2, MultiXactStatus status2)
void TruncateMultiXact(MultiXactId newOldestMulti, Oid newOldestMultiDB)
bool check_multixact_offset_buffers(int *newval, void **extra, GucSource source)
bool check_multixact_member_buffers(int *newval, void **extra, GucSource source)
void AtEOXact_MultiXact(void)
#define MULTIXACT_MEMBER_HIGH_THRESHOLD
static SlruCtlData MultiXactMemberCtlData
#define debug_elog2(a, b)
void StartupMultiXact(void)
void SetMultiXactIdLimit(MultiXactId oldest_datminmxid, Oid oldest_datoid)
int GetMultiXactIdMembers(MultiXactId multi, MultiXactMember **members, bool from_pgupgrade, bool isLockOnly)
#define MultiXactIdIsValid(multi)
#define XLOG_MULTIXACT_ZERO_MEM_PAGE
#define XLOG_MULTIXACT_ZERO_OFF_PAGE
@ MultiXactStatusForShare
@ MultiXactStatusForNoKeyUpdate
@ MultiXactStatusNoKeyUpdate
@ MultiXactStatusForUpdate
@ MultiXactStatusForKeyShare
#define ISUPDATE_from_mxstatus(status)
#define InvalidMultiXactId
#define XLOG_MULTIXACT_TRUNCATE_ID
#define SizeOfMultiXactCreate
#define SizeOfMultiXactTruncate
#define XLOG_MULTIXACT_CREATE_ID
struct MultiXactMember MultiXactMember
static int64 MultiXactIdToOffsetSegment(MultiXactId multi)
static int64 MXOffsetToMemberSegment(MultiXactOffset offset)
#define MXACT_MEMBER_BITS_PER_XACT
static int MXOffsetToFlagsBitShift(MultiXactOffset32 offset)
#define MXACT_MEMBER_XACT_BITMASK
static int64 MXOffsetToMemberPage(MultiXactOffset32 offset)
#define MULTIXACT_OFFSETS_PER_PAGE
static int MXOffsetToMemberOffset(MultiXactOffset32 offset)
static int MultiXactIdToOffsetEntry(MultiXactId multi)
static int64 MultiXactIdToOffsetPage(MultiXactId multi)
#define MULTIXACT_MEMBERS_PER_PAGE
static int MXOffsetToFlagsOffset(MultiXactOffset32 offset)
#define ERRCODE_DATA_CORRUPTED
static rewind_source * source
static char buf[DEFAULT_XLOG_SEG_SIZE]
void SendPostmasterSignal(PMSignalReason reason)
@ PMSIGNAL_START_AUTOVAC_LAUNCHER
#define qsort(a, b, c, d)
#define DELAY_CHKPT_START
bool TransactionIdIsInProgress(TransactionId xid)
Size add_size(Size s1, Size s2)
void * ShmemInitStruct(const char *name, Size size, bool *foundPtr)
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)
int SimpleLruReadPage_ReadOnly(SlruCtl ctl, int64 pageno, TransactionId xid)
void SimpleLruWriteAll(SlruCtl ctl, bool allow_redirtied)
bool SimpleLruDoesPhysicalPageExist(SlruCtl ctl, int64 pageno)
bool SlruScanDirectory(SlruCtl ctl, SlruScanCallback callback, void *data)
int SimpleLruReadPage(SlruCtl ctl, int64 pageno, bool write_ok, TransactionId xid)
int SlruSyncFileTag(SlruCtl ctl, const FileTag *ftag, char *path)
int SimpleLruZeroPage(SlruCtl ctl, int64 pageno)
void SimpleLruZeroAndWritePage(SlruCtl ctl, int64 pageno)
void SimpleLruTruncate(SlruCtl ctl, int64 cutoffPage)
Size SimpleLruShmemSize(int nslots, int nlsns)
bool check_slru_buffers(const char *name, int *newval)
static LWLock * SimpleLruGetBankLock(SlruCtl ctl, int64 pageno)
#define SlruPagePrecedesUnitTests(ctl, per_page)
void appendStringInfo(StringInfo str, const char *fmt,...)
void appendStringInfoChar(StringInfo str, char ch)
void initStringInfo(StringInfo str)
MultiXactId multiWrapLimit
MultiXactId multiStopLimit
MultiXactId multiWarnLimit
MultiXactId multiVacLimit
MultiXactOffset nextOffset
MultiXactId oldestMultiXactId
MultiXactId perBackendXactIds[FLEXIBLE_ARRAY_MEMBER]
MultiXactOffset oldestOffset
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
int64 earliestExistingPage
MultiXactMember members[FLEXIBLE_ARRAY_MEMBER]
MultiXactOffset startTruncMemb
MultiXactOffset endTruncMemb
MultiXactId startTruncOff
@ SYNC_HANDLER_MULTIXACT_MEMBER
@ SYNC_HANDLER_MULTIXACT_OFFSET
bool TransactionIdDidCommit(TransactionId transactionId)
#define TransactionIdEquals(id1, id2)
#define TransactionIdIsValid(xid)
static bool TransactionIdPrecedes(TransactionId id1, TransactionId id2)
ProcNumber TwoPhaseGetDummyProcNumber(FullTransactionId fxid, bool lock_held)
void RegisterTwoPhaseRecord(TwoPhaseRmgrId rmid, uint16 info, const void *data, uint32 len)
#define TWOPHASE_RM_MULTIXACT_ID
void AdvanceNextFullTransactionIdPastXid(TransactionId xid)
bool IsTransactionState(void)
bool TransactionIdIsCurrentTransactionId(TransactionId xid)
bool RecoveryInProgress(void)
void XLogFlush(XLogRecPtr record)
XLogRecPtr XLogSimpleInsertInt64(RmgrId rmid, uint8 info, int64 value)
XLogRecPtr XLogInsert(RmgrId rmid, uint8 info)
void XLogRegisterData(const void *data, uint32 len)
void XLogBeginInsert(void)
#define XLogRecGetInfo(decoder)
#define XLogRecGetData(decoder)
#define XLogRecGetXid(decoder)
#define XLogRecHasAnyBlockRefs(decoder)