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 with offset (%" PRIu64
") has zero members",
1270 if (nextMXOffset < offset)
1273 errmsg(
"MultiXact %u has offset (%" PRIu64
") greater than its next offset (%" PRIu64
")",
1274 multi, offset, nextMXOffset)));
1275 if (nextMXOffset - offset > INT32_MAX)
1278 errmsg(
"MultiXact %u has too many members (%" PRIu64
")",
1279 multi, nextMXOffset - offset)));
1280 length = nextMXOffset - offset;
1285 for (
int i = 0;
i < length;
i++, offset++)
1296 if (pageno != prev_pageno)
1306 if (newlock != lock)
1315 prev_pageno = pageno;
1326 ptr[
i].
xid = *xactptr;
1356 if (member1.
xid > member2.
xid)
1358 if (member1.
xid < member2.
xid)
1407 return entry->
multi;
1435 if (entry->
multi == multi)
1443 memcpy(ptr, entry->
members, size);
1483 "MultiXact cache context",
1492 entry->
multi = multi;
1525 return "fornokeyupd";
1533 elog(
ERROR,
"unrecognized multixact status %d", status);
1541 static char *
str = NULL;
1553 for (
i = 1;
i < nmembers;
i++)
1714#define SHARED_MULTIXACT_STATE_SIZE \
1715 add_size(offsetof(MultiXactStateData, perBackendXactIds), \
1716 mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
1737 "pg_multixact/offsets", LWTRANCHE_MULTIXACTOFFSET_BUFFER,
1738 LWTRANCHE_MULTIXACTOFFSET_SLRU,
1744 "pg_multixact/members", LWTRANCHE_MULTIXACTMEMBER_BUFFER,
1745 LWTRANCHE_MULTIXACTMEMBER_SLRU,
1923 MemSet(xidptr, 0, BLCKSZ - memberoff);
1962 "MultiXact: checkpoint is nextMulti %u, nextOffset %" PRIu64
", oldestMulti %u in DB %u",
1963 *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB);
1972 TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(
true);
1982 TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(
true);
1999 nextMulti, nextMultiOffset);
2039 multiStopLimit = multiWrapLimit - 3000000;
2053 multiWarnLimit = multiWrapLimit - 40000000;
2082 (
errmsg_internal(
"MultiXactId wrap limit is %u, limited by database with OID %u",
2083 multiWrapLimit, oldest_datoid)));
2119 char *oldest_datname;
2133 oldest_datname = NULL;
2137 (
errmsg_plural(
"database \"%s\" must be vacuumed before %u more MultiXactId is used",
2138 "database \"%s\" must be vacuumed before %u more MultiXactIds are used",
2139 multiWrapLimit - curMulti,
2141 multiWrapLimit - curMulti),
2142 errhint(
"To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2143 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2146 (
errmsg_plural(
"database with OID %u must be vacuumed before %u more MultiXactId is used",
2147 "database with OID %u must be vacuumed before %u more MultiXactIds are used",
2148 multiWrapLimit - curMulti,
2150 multiWrapLimit - curMulti),
2151 errhint(
"To avoid MultiXactId assignment failures, execute a database-wide VACUUM in that database.\n"
2152 "You might also need to commit or roll back old prepared transactions, or drop stale replication slots.")));
2252 while (nmembers > 0)
2263 if (flagsoff == 0 && flagsbit == 0)
2323 oldestMXact = thisoldest;
2327 oldestMXact = thisoldest;
2346 bool oldestOffsetKnown =
false;
2369 if (oldestMultiXactId == nextMXact)
2375 oldestOffset = nextOffset;
2376 oldestOffsetKnown =
true;
2395 if (oldestOffsetKnown)
2401 (
errmsg(
"MultiXact member truncation is disabled because oldest checkpointed MultiXact %u does not exist on disk",
2402 oldestMultiXactId)));
2408 if (oldestOffsetKnown)
2481 *multixacts = nextMultiXactId - *oldestMultiXactId;
2516 uint32 victim_multixacts;
2525 GetMultiXactInfo(&multixacts, &nextOffset, &oldestMultiXactId, &oldestOffset);
2526 members = nextOffset - oldestOffset;
2548 if (fraction >= 1.0)
2551 victim_multixacts = multixacts * fraction;
2552 result = multixacts - victim_multixacts;
2702 if (oldestMulti == nextMulti)
2705 oldestOffset = nextOffset;
2710 (
errmsg(
"oldest MultiXact %u not found, earliest MultiXact %u, skipping truncation",
2711 oldestMulti, earliest)));
2720 if (newOldestMulti == nextMulti)
2723 newOldestOffset = nextOffset;
2728 (
errmsg(
"cannot truncate up to MultiXact %u because it does not exist on disk, skipping truncation",
2734 elog(
DEBUG1,
"performing multixact truncation: "
2735 "offsets [%u, %u), offsets segments [%" PRIx64
", %" PRIx64
"), "
2736 "members [%" PRIu64
", %" PRIu64
"), members segments [%" PRIx64
", %" PRIx64
")",
2737 oldestMulti, newOldestMulti,
2740 oldestOffset, newOldestOffset,
2763 oldestMulti, newOldestMulti,
2764 oldestOffset, newOldestOffset);
2823 return page1 < page2;
2945 elog(
DEBUG1,
"replaying multixact truncation: "
2946 "offsets [%u, %u), offsets segments [%" PRIx64
", %" PRIx64
"), "
2947 "members [%" PRIu64
", %" PRIu64
"), members segments [%" PRIx64
", %" PRIx64
")",
2979 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)
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)
void GetMultiXactInfo(uint32 *multixacts, MultiXactOffset *nextOffset, MultiXactId *oldestMultiXactId, MultiXactOffset *oldestOffset)
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)