#include "postgres.h"
#include "access/multixact.h"
#include "access/slru.h"
#include "access/transam.h"
#include "access/twophase.h"
#include "access/twophase_rmgr.h"
#include "access/xact.h"
#include "catalog/pg_type.h"
#include "commands/dbcommands.h"
#include "funcapi.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "storage/lmgr.h"
#include "storage/pmsignal.h"
#include "storage/procarray.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
Go to the source code of this file.
#define debug_elog2 | ( | a, | ||
b | ||||
) |
Definition at line 279 of file multixact.c.
Referenced by CreateMultiXactId(), MultiXactIdIsRunning(), MultiXactShmemInit(), mXactCacheGetById(), mXactCacheGetBySet(), and mXactCachePut().
#define debug_elog3 | ( | a, | ||
b, | ||||
c | ||||
) |
Definition at line 280 of file multixact.c.
Referenced by CreateMultiXactId(), GetMultiXactIdMembers(), GetNewMultiXactId(), MultiXactAdvanceNextMXact(), MultiXactIdCreate(), MultiXactIdExpand(), MultiXactIdIsRunning(), mXactCacheGetById(), mXactCacheGetBySet(), and mXactCachePut().
#define debug_elog4 | ( | a, | ||
b, | ||||
c, | ||||
d | ||||
) |
Definition at line 281 of file multixact.c.
Referenced by GetNewMultiXactId(), MultiXactIdExpand(), MultiXactIdIsRunning(), MultiXactIdSetOldestMember(), MultiXactIdSetOldestVisible(), and MultiXactSetNextMXact().
Definition at line 282 of file multixact.c.
Referenced by MultiXactIdExpand().
Definition at line 283 of file multixact.c.
Referenced by MultiXactGetCheckptMulti().
#define MaxOldestSlot (MaxBackends + max_prepared_xacts) |
Definition at line 236 of file multixact.c.
#define MULTIXACT_FLAGBYTES_PER_GROUP 4 |
Definition at line 124 of file multixact.c.
#define MULTIXACT_MEMBERGROUP_SIZE (sizeof(TransactionId) * MULTIXACT_MEMBERS_PER_MEMBERGROUP + MULTIXACT_FLAGBYTES_PER_GROUP) |
Definition at line 128 of file multixact.c.
#define MULTIXACT_MEMBERGROUPS_PER_PAGE (BLCKSZ / MULTIXACT_MEMBERGROUP_SIZE) |
Definition at line 130 of file multixact.c.
#define MULTIXACT_MEMBERS_PER_MEMBERGROUP (MULTIXACT_FLAGBYTES_PER_GROUP * MXACT_MEMBER_FLAGS_PER_BYTE) |
Definition at line 125 of file multixact.c.
#define MULTIXACT_MEMBERS_PER_PAGE (MULTIXACT_MEMBERGROUPS_PER_PAGE * MULTIXACT_MEMBERS_PER_MEMBERGROUP) |
Definition at line 131 of file multixact.c.
Referenced by ExtendMultiXactMember().
#define MULTIXACT_OFFSETS_PER_PAGE (BLCKSZ / sizeof(MultiXactOffset)) |
Definition at line 99 of file multixact.c.
#define MultiXactIdToOffsetEntry | ( | xid | ) | ((xid) % (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE) |
Definition at line 103 of file multixact.c.
Referenced by ExtendMultiXactOffset(), GetMultiXactIdMembers(), RecordNewMultiXact(), StartupMultiXact(), and TruncateMultiXact().
#define MultiXactIdToOffsetPage | ( | xid | ) | ((xid) / (MultiXactOffset) MULTIXACT_OFFSETS_PER_PAGE) |
Definition at line 101 of file multixact.c.
Referenced by ExtendMultiXactOffset(), GetMultiXactIdMembers(), RecordNewMultiXact(), StartupMultiXact(), and TruncateMultiXact().
#define MultiXactMemberCtl (&MultiXactMemberCtlData) |
Definition at line 159 of file multixact.c.
Referenced by BootStrapMultiXact(), CheckPointMultiXact(), GetMultiXactIdMembers(), multixact_redo(), MultiXactShmemInit(), RecordNewMultiXact(), ShutdownMultiXact(), StartupMultiXact(), TruncateMultiXact(), and ZeroMultiXactMemberPage().
#define MultiXactOffsetCtl (&MultiXactOffsetCtlData) |
Definition at line 158 of file multixact.c.
Referenced by BootStrapMultiXact(), CheckPointMultiXact(), GetMultiXactIdMembers(), multixact_redo(), MultiXactShmemInit(), RecordNewMultiXact(), ShutdownMultiXact(), StartupMultiXact(), TruncateMultiXact(), and ZeroMultiXactOffsetPage().
#define MXACT_MEMBER_BITS_PER_XACT 8 |
Definition at line 119 of file multixact.c.
#define MXACT_MEMBER_FLAGS_PER_BYTE 1 |
Definition at line 120 of file multixact.c.
#define MXACT_MEMBER_XACT_BITMASK ((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) |
Definition at line 121 of file multixact.c.
Referenced by GetMultiXactIdMembers().
#define MXOffsetToFlagsBitShift | ( | xid | ) |
(((xid) % (TransactionId) MULTIXACT_MEMBERS_PER_MEMBERGROUP) * \ MXACT_MEMBER_BITS_PER_XACT)
Definition at line 142 of file multixact.c.
Referenced by ExtendMultiXactMember(), GetMultiXactIdMembers(), and RecordNewMultiXact().
#define MXOffsetToFlagsOffset | ( | xid | ) |
((((xid) / (TransactionId) MULTIXACT_MEMBERS_PER_MEMBERGROUP) % \ (TransactionId) MULTIXACT_MEMBERGROUPS_PER_PAGE) * \ (TransactionId) MULTIXACT_MEMBERGROUP_SIZE)
Definition at line 138 of file multixact.c.
Referenced by ExtendMultiXactMember(), GetMultiXactIdMembers(), RecordNewMultiXact(), and StartupMultiXact().
#define MXOffsetToMemberOffset | ( | xid | ) |
(MXOffsetToFlagsOffset(xid) + MULTIXACT_FLAGBYTES_PER_GROUP + \ ((xid) % MULTIXACT_MEMBERS_PER_MEMBERGROUP) * sizeof(TransactionId))
Definition at line 147 of file multixact.c.
Referenced by GetMultiXactIdMembers(), RecordNewMultiXact(), and StartupMultiXact().
#define MXOffsetToMemberPage | ( | xid | ) | ((xid) / (TransactionId) MULTIXACT_MEMBERS_PER_PAGE) |
Definition at line 135 of file multixact.c.
Referenced by ExtendMultiXactMember(), GetMultiXactIdMembers(), RecordNewMultiXact(), StartupMultiXact(), and TruncateMultiXact().
#define SHARED_MULTIXACT_STATE_SIZE |
add_size(sizeof(MultiXactStateData), \ mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot))
Referenced by MultiXactShmemInit().
typedef struct MultiXactStateData MultiXactStateData |
typedef struct mXactCacheEnt mXactCacheEnt |
typedef struct mxtruncinfo mxtruncinfo |
void AtEOXact_MultiXact | ( | void | ) |
Definition at line 1455 of file multixact.c.
References MyBackendId, OldestMemberMXactId, and OldestVisibleMXactId.
Referenced by AbortTransaction(), and CommitTransaction().
{ /* * Reset our OldestMemberMXactId and OldestVisibleMXactId values, both of * which should only be valid while within a transaction. * * We assume that storing a MultiXactId is atomic and so we need not take * MultiXactGenLock to do this. */ OldestMemberMXactId[MyBackendId] = InvalidMultiXactId; OldestVisibleMXactId[MyBackendId] = InvalidMultiXactId; /* * Discard the local MultiXactId cache. Since MXactContext was created as * a child of TopTransactionContext, we needn't delete it explicitly. */ MXactContext = NULL; MXactCache = NULL; }
void AtPrepare_MultiXact | ( | void | ) |
Definition at line 1483 of file multixact.c.
References MultiXactIdIsValid, MyBackendId, OldestMemberMXactId, RegisterTwoPhaseRecord(), and TWOPHASE_RM_MULTIXACT_ID.
Referenced by PrepareTransaction().
{ MultiXactId myOldestMember = OldestMemberMXactId[MyBackendId]; if (MultiXactIdIsValid(myOldestMember)) RegisterTwoPhaseRecord(TWOPHASE_RM_MULTIXACT_ID, 0, &myOldestMember, sizeof(MultiXactId)); }
void BootStrapMultiXact | ( | void | ) |
Definition at line 1654 of file multixact.c.
References Assert, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactMemberControlLock, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, SimpleLruWritePage(), ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().
Referenced by BootStrapXLOG().
{ int slotno; LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE); /* Create and zero the first page of the offsets log */ slotno = ZeroMultiXactOffsetPage(0, false); /* Make sure it's written out */ SimpleLruWritePage(MultiXactOffsetCtl, slotno); Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]); LWLockRelease(MultiXactOffsetControlLock); LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE); /* Create and zero the first page of the members log */ slotno = ZeroMultiXactMemberPage(0, false); /* Make sure it's written out */ SimpleLruWritePage(MultiXactMemberCtl, slotno); Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]); LWLockRelease(MultiXactMemberControlLock); }
void CheckPointMultiXact | ( | void | ) |
Definition at line 1847 of file multixact.c.
References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruFlush().
Referenced by CheckPointGuts().
{ TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(true); /* Flush dirty MultiXact pages to disk */ SimpleLruFlush(MultiXactOffsetCtl, true); SimpleLruFlush(MultiXactMemberCtl, true); TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(true); }
static MultiXactId CreateMultiXactId | ( | int | nmembers, | |
MultiXactMember * | members | |||
) | [static] |
Definition at line 672 of file multixact.c.
References XLogRecData::buffer, XLogRecData::data, DEBUG2, debug_elog2, debug_elog3, END_CRIT_SECTION, GetNewMultiXactId(), InvalidMultiXactId, XLogRecData::len, xl_multixact_create::mid, xl_multixact_create::moff, mXactCacheEnt::multi, MultiXactIdIsValid, mXactCacheGetBySet(), mXactCachePut(), mxid_to_string(), XLogRecData::next, xl_multixact_create::nmembers, RecordNewMultiXact(), XLOG_MULTIXACT_CREATE_ID, and XLogInsert().
Referenced by MultiXactIdCreate(), and MultiXactIdExpand().
{ MultiXactId multi; MultiXactOffset offset; XLogRecData rdata[2]; xl_multixact_create xlrec; debug_elog3(DEBUG2, "Create: %s", mxid_to_string(InvalidMultiXactId, nmembers, members)); /* * See if the same set of members already exists in our cache; if so, just * re-use that MultiXactId. (Note: it might seem that looking in our * cache is insufficient, and we ought to search disk to see if a * duplicate definition already exists. But since we only ever create * MultiXacts containing our own XID, in most cases any such MultiXacts * were in fact created by us, and so will be in our cache. There are * corner cases where someone else added us to a MultiXact without our * knowledge, but it's not worth checking for.) */ multi = mXactCacheGetBySet(nmembers, members); if (MultiXactIdIsValid(multi)) { debug_elog2(DEBUG2, "Create: in cache!"); return multi; } /* * Assign the MXID and offsets range to use, and make sure there is space * in the OFFSETs and MEMBERs files. NB: this routine does * START_CRIT_SECTION(). */ multi = GetNewMultiXactId(nmembers, &offset); /* * Make an XLOG entry describing the new MXID. * * Note: we need not flush this XLOG entry to disk before proceeding. The * only way for the MXID to be referenced from any data page is for * heap_lock_tuple() to have put it there, and heap_lock_tuple() generates * an XLOG record that must follow ours. The normal LSN interlock between * the data page and that XLOG record will ensure that our XLOG record * reaches disk first. If the SLRU members/offsets data reaches disk * sooner than the XLOG record, we do not care because we'll overwrite it * with zeroes unless the XLOG record is there too; see notes at top of * this file. */ xlrec.mid = multi; xlrec.moff = offset; xlrec.nmembers = nmembers; /* * XXX Note: there's a lot of padding space in MultiXactMember. We could * find a more compact representation of this Xlog record -- perhaps all the * status flags in one XLogRecData, then all the xids in another one? Not * clear that it's worth the trouble though. */ rdata[0].data = (char *) (&xlrec); rdata[0].len = SizeOfMultiXactCreate; rdata[0].buffer = InvalidBuffer; rdata[0].next = &(rdata[1]); rdata[1].data = (char *) members; rdata[1].len = nmembers * sizeof(MultiXactMember); rdata[1].buffer = InvalidBuffer; rdata[1].next = NULL; (void) XLogInsert(RM_MULTIXACT_ID, XLOG_MULTIXACT_CREATE_ID, rdata); /* Now enter the information into the OFFSETs and MEMBERs logs */ RecordNewMultiXact(multi, offset, nmembers, members); /* Done with critical section */ END_CRIT_SECTION(); /* Store the new MultiXactId in the local cache, too */ mXactCachePut(multi, nmembers, members); debug_elog2(DEBUG2, "Create: all done"); return multi; }
static void ExtendMultiXactMember | ( | MultiXactOffset | offset, | |
int | nmembers | |||
) | [static] |
Definition at line 2076 of file multixact.c.
References LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MULTIXACT_MEMBERS_PER_PAGE, MultiXactMemberControlLock, MXOffsetToFlagsBitShift, MXOffsetToFlagsOffset, MXOffsetToMemberPage, and ZeroMultiXactMemberPage().
Referenced by GetNewMultiXactId().
{ /* * It's possible that the members span more than one page of the members * file, so we loop to ensure we consider each page. The coding is not * optimal if the members span several pages, but that seems unusual * enough to not worry much about. */ while (nmembers > 0) { int flagsoff; int flagsbit; int difference; /* * Only zero when at first entry of a page. */ flagsoff = MXOffsetToFlagsOffset(offset); flagsbit = MXOffsetToFlagsBitShift(offset); if (flagsoff == 0 && flagsbit == 0) { int pageno; pageno = MXOffsetToMemberPage(offset); LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE); /* Zero the page and make an XLOG entry about it */ ZeroMultiXactMemberPage(pageno, true); LWLockRelease(MultiXactMemberControlLock); } /* Advance to next page (OK if nmembers goes negative) */ difference = MULTIXACT_MEMBERS_PER_PAGE - offset % MULTIXACT_MEMBERS_PER_PAGE; offset += difference; nmembers -= difference; } }
static void ExtendMultiXactOffset | ( | MultiXactId | multi | ) | [static] |
Definition at line 2046 of file multixact.c.
References FirstMultiXactId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactOffsetControlLock, and ZeroMultiXactOffsetPage().
Referenced by GetNewMultiXactId().
{ int pageno; /* * No work except at first MultiXactId of a page. But beware: just after * wraparound, the first MultiXactId of page zero is FirstMultiXactId. */ if (MultiXactIdToOffsetEntry(multi) != 0 && multi != FirstMultiXactId) return; pageno = MultiXactIdToOffsetPage(multi); LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE); /* Zero the page and make an XLOG entry about it */ ZeroMultiXactOffsetPage(pageno, true); LWLockRelease(MultiXactOffsetControlLock); }
int GetMultiXactIdMembers | ( | MultiXactId | multi, | |
MultiXactMember ** | members, | |||
bool | allow_old | |||
) |
Definition at line 1030 of file multixact.c.
References Assert, DEBUG1, DEBUG2, debug_elog3, ereport, errcode(), errmsg(), ERROR, FirstMultiXactId, i, LW_EXCLUSIVE, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactIdSetOldestVisible(), MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactMemberControlLock, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, MXACT_MEMBER_XACT_BITMASK, mXactCacheGetById(), mXactCachePut(), mxid_to_string(), MXOffsetToFlagsBitShift, MXOffsetToFlagsOffset, MXOffsetToMemberOffset, MXOffsetToMemberPage, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactId, palloc(), pg_usleep(), SimpleLruReadPage(), MultiXactMember::status, TransactionIdIsValid, and MultiXactMember::xid.
Referenced by Do_MultiXactIdWait(), GetMultiXactIdHintBits(), heap_lock_tuple(), MultiXactIdExpand(), MultiXactIdGetUpdateXid(), MultiXactIdIsRunning(), pg_get_multixact_members(), and pgrowlocks().
{ int pageno; int prev_pageno; int entryno; int slotno; MultiXactOffset *offptr; MultiXactOffset offset; int length; int truelength; int i; MultiXactId oldestMXact; MultiXactId nextMXact; MultiXactId tmpMXact; MultiXactOffset nextOffset; MultiXactMember *ptr; debug_elog3(DEBUG2, "GetMembers: asked for %u", multi); Assert(MultiXactIdIsValid(multi)); /* See if the MultiXactId is in the local cache */ length = mXactCacheGetById(multi, members); if (length >= 0) { debug_elog3(DEBUG2, "GetMembers: found %s in the cache", mxid_to_string(multi, length, *members)); return length; } /* Set our OldestVisibleMXactId[] entry if we didn't already */ MultiXactIdSetOldestVisible(); /* * We check known limits on MultiXact before resorting to the SLRU area. * * An ID older than MultiXactState->oldestMultiXactId cannot possibly be * useful; it should have already been frozen by vacuum. We've truncated * the on-disk structures anyway. Returning the wrong values could lead to * an incorrect visibility result. However, to support pg_upgrade we need * to allow an empty set to be returned regardless, if the caller is * willing to accept it; the caller is expected to check that it's an * allowed condition (such as ensuring that the infomask bits set on the * tuple are consistent with the pg_upgrade scenario). If the caller is * expecting this to be called only on recently created multis, then we * raise an error. * * Conversely, an ID >= nextMXact shouldn't ever be seen here; if it is * seen, it implies undetected ID wraparound has occurred. This raises * a hard error. * * Shared lock is enough here since we aren't modifying any global state. * Acquire it just long enough to grab the current counter values. We may * need both nextMXact and nextOffset; see below. */ LWLockAcquire(MultiXactGenLock, LW_SHARED); oldestMXact = MultiXactState->oldestMultiXactId; nextMXact = MultiXactState->nextMXact; nextOffset = MultiXactState->nextOffset; LWLockRelease(MultiXactGenLock); if (MultiXactIdPrecedes(multi, oldestMXact)) { ereport(allow_old ? DEBUG1 : ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("MultiXactId %u does no longer exist -- apparent wraparound", multi))); return -1; } if (!MultiXactIdPrecedes(multi, nextMXact)) ereport(ERROR, (errcode(ERRCODE_INTERNAL_ERROR), errmsg("MultiXactId %u has not been created yet -- apparent wraparound", multi))); /* * Find out the offset at which we need to start reading MultiXactMembers * and the number of members in the multixact. We determine the latter as * the difference between this multixact's starting offset and the next * one's. However, there are some corner cases to worry about: * * 1. This multixact may be the latest one created, in which case there is * no next one to look at. In this case the nextOffset value we just * saved is the correct endpoint. * * 2. The next multixact may still be in process of being filled in: that * is, another process may have done GetNewMultiXactId but not yet written * the offset entry for that ID. In that scenario, it is guaranteed that * the offset entry for that multixact exists (because GetNewMultiXactId * won't release MultiXactGenLock until it does) but contains zero * (because we are careful to pre-zero offset pages). Because * GetNewMultiXactId will never return zero as the starting offset for a * multixact, when we read zero as the next multixact's offset, we know we * have this case. We sleep for a bit and try again. * * 3. Because GetNewMultiXactId increments offset zero to offset one to * handle case #2, there is an ambiguity near the point of offset * wraparound. If we see next multixact's offset is one, is that our * multixact's actual endpoint, or did it end at zero with a subsequent * increment? We handle this using the knowledge that if the zero'th * member slot wasn't filled, it'll contain zero, and zero isn't a valid * transaction ID so it can't be a multixact member. Therefore, if we * read a zero from the members array, just ignore it. * * This is all pretty messy, but the mess occurs only in infrequent corner * cases, so it seems better than holding the MultiXactGenLock for a long * time on every multixact creation. */ retry: LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE); pageno = MultiXactIdToOffsetPage(multi); entryno = MultiXactIdToOffsetEntry(multi); slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi); offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno]; offptr += entryno; offset = *offptr; Assert(offset != 0); /* * Use the same increment rule as GetNewMultiXactId(), that is, don't * handle wraparound explicitly until needed. */ tmpMXact = multi + 1; if (nextMXact == tmpMXact) { /* Corner case 1: there is no next multixact */ length = nextOffset - offset; } else { MultiXactOffset nextMXOffset; /* handle wraparound if needed */ if (tmpMXact < FirstMultiXactId) tmpMXact = FirstMultiXactId; prev_pageno = pageno; pageno = MultiXactIdToOffsetPage(tmpMXact); entryno = MultiXactIdToOffsetEntry(tmpMXact); if (pageno != prev_pageno) slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, tmpMXact); offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno]; offptr += entryno; nextMXOffset = *offptr; if (nextMXOffset == 0) { /* Corner case 2: next multixact is still being filled in */ LWLockRelease(MultiXactOffsetControlLock); pg_usleep(1000L); goto retry; } length = nextMXOffset - offset; } LWLockRelease(MultiXactOffsetControlLock); ptr = (MultiXactMember *) palloc(length * sizeof(MultiXactMember)); *members = ptr; /* Now get the members themselves. */ LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE); truelength = 0; prev_pageno = -1; for (i = 0; i < length; i++, offset++) { TransactionId *xactptr; uint32 *flagsptr; int flagsoff; int bshift; int memberoff; pageno = MXOffsetToMemberPage(offset); memberoff = MXOffsetToMemberOffset(offset); if (pageno != prev_pageno) { slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi); prev_pageno = pageno; } xactptr = (TransactionId *) (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff); if (!TransactionIdIsValid(*xactptr)) { /* Corner case 3: we must be looking at unused slot zero */ Assert(offset == 0); continue; } flagsoff = MXOffsetToFlagsOffset(offset); bshift = MXOffsetToFlagsBitShift(offset); flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff); ptr[truelength].xid = *xactptr; ptr[truelength].status = (*flagsptr >> bshift) & MXACT_MEMBER_XACT_BITMASK; truelength++; } LWLockRelease(MultiXactMemberControlLock); /* * Copy the result into the local cache. */ mXactCachePut(multi, truelength, ptr); debug_elog3(DEBUG2, "GetMembers: no cache for %s", mxid_to_string(multi, truelength, ptr)); return truelength; }
static MultiXactId GetNewMultiXactId | ( | int | nmembers, | |
MultiXactOffset * | offset | |||
) | [static] |
Definition at line 856 of file multixact.c.
References Assert, DEBUG2, debug_elog3, debug_elog4, elog, ereport, errcode(), errhint(), errmsg(), ERROR, ExtendMultiXactMember(), ExtendMultiXactOffset(), FirstMultiXactId, get_database_name(), IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactStateData::multiStopLimit, MultiXactStateData::multiVacLimit, MultiXactStateData::multiWarnLimit, MultiXactStateData::multiWrapLimit, MultiXactGenLock, MultiXactIdIsValid, MultiXactIdPrecedes(), MyBackendId, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, OldestMemberMXactId, MultiXactStateData::oldestMultiXactDB, PMSIGNAL_START_AUTOVAC_LAUNCHER, RecoveryInProgress(), SendPostmasterSignal(), START_CRIT_SECTION, and WARNING.
Referenced by CreateMultiXactId().
{ MultiXactId result; MultiXactOffset nextOffset; debug_elog3(DEBUG2, "GetNew: for %d xids", nmembers); /* MultiXactIdSetOldestMember() must have been called already */ Assert(MultiXactIdIsValid(OldestMemberMXactId[MyBackendId])); /* safety check, we should never get this far in a HS slave */ if (RecoveryInProgress()) elog(ERROR, "cannot assign MultiXactIds during recovery"); LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE); /* Handle wraparound of the nextMXact counter */ if (MultiXactState->nextMXact < FirstMultiXactId) MultiXactState->nextMXact = FirstMultiXactId; /* Assign the MXID */ result = MultiXactState->nextMXact; /*---------- * Check to see if it's safe to assign another MultiXactId. This protects * against catastrophic data loss due to multixact wraparound. The basic * rules are: * * If we're past multiVacLimit, start trying to force autovacuum cycles. * If we're past multiWarnLimit, start issuing warnings. * If we're past multiStopLimit, refuse to create new MultiXactIds. * * Note these are pretty much the same protections in GetNewTransactionId. *---------- */ if (!MultiXactIdPrecedes(result, MultiXactState->multiVacLimit)) { /* * For safety's sake, we release MultiXactGenLock while sending * signals, warnings, etc. This is not so much because we care about * preserving concurrency in this situation, as to avoid any * possibility of deadlock while doing get_database_name(). First, * copy all the shared values we'll need in this path. */ MultiXactId multiWarnLimit = MultiXactState->multiWarnLimit; MultiXactId multiStopLimit = MultiXactState->multiStopLimit; MultiXactId multiWrapLimit = MultiXactState->multiWrapLimit; Oid oldest_datoid = MultiXactState->oldestMultiXactDB; LWLockRelease(MultiXactGenLock); /* * To avoid swamping the postmaster with signals, we issue the autovac * request only once per 64K transaction starts. This still gives * plenty of chances before we get into real trouble. */ if (IsUnderPostmaster && (result % 65536) == 0) SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER); if (IsUnderPostmaster && !MultiXactIdPrecedes(result, multiStopLimit)) { char *oldest_datname = get_database_name(oldest_datoid); /* complain even if that DB has disappeared */ if (oldest_datname) ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("database is not accepting commands that generate new MultiXactIds to avoid wraparound data loss in database \"%s\"", oldest_datname), errhint("Execute a database-wide VACUUM in that database.\n" "You might also need to commit or roll back old prepared transactions."))); else ereport(ERROR, (errcode(ERRCODE_PROGRAM_LIMIT_EXCEEDED), errmsg("database is not accepting commands that generate new MultiXactIds to avoid wraparound data loss in database with OID %u", oldest_datoid), errhint("Execute a database-wide VACUUM in that database.\n" "You might also need to commit or roll back old prepared transactions."))); } else if (!MultiXactIdPrecedes(result, multiWarnLimit)) { char *oldest_datname = get_database_name(oldest_datoid); /* complain even if that DB has disappeared */ if (oldest_datname) ereport(WARNING, (errmsg("database \"%s\" must be vacuumed before %u more MultiXactIds are used", oldest_datname, multiWrapLimit - result), errhint("Execute a database-wide VACUUM in that database.\n" "You might also need to commit or roll back old prepared transactions."))); else ereport(WARNING, (errmsg("database with OID %u must be vacuumed before %u more MultiXactIds are used", oldest_datoid, multiWrapLimit - result), errhint("Execute a database-wide VACUUM in that database.\n" "You might also need to commit or roll back old prepared transactions."))); } /* Re-acquire lock and start over */ LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE); result = MultiXactState->nextMXact; if (result < FirstMultiXactId) result = FirstMultiXactId; } /* Make sure there is room for the MXID in the file. */ ExtendMultiXactOffset(result); /* * Reserve the members space, similarly to above. Also, be careful not to * return zero as the starting offset for any multixact. See * GetMultiXactIdMembers() for motivation. */ nextOffset = MultiXactState->nextOffset; if (nextOffset == 0) { *offset = 1; nmembers++; /* allocate member slot 0 too */ } else *offset = nextOffset; ExtendMultiXactMember(nextOffset, nmembers); /* * Critical section from here until caller has written the data into the * just-reserved SLRU space; we don't want to error out with a partly * written MultiXact structure. (In particular, failing to write our * start offset after advancing nextMXact would effectively corrupt the * previous MultiXact.) */ START_CRIT_SECTION(); /* * Advance counters. As in GetNewTransactionId(), this must not happen * until after file extension has succeeded! * * We don't care about MultiXactId wraparound here; it will be handled by * the next iteration. But note that nextMXact may be InvalidMultiXactId * or the first value on a segment-beginning page after this routine exits, * so anyone else looking at the variable must be prepared to deal with * either case. Similarly, nextOffset may be zero, but we won't use that * as the actual start offset of the next multixact. */ (MultiXactState->nextMXact)++; MultiXactState->nextOffset += nmembers; LWLockRelease(MultiXactGenLock); debug_elog4(DEBUG2, "GetNew: returning %u offset %u", result, *offset); return result; }
MultiXactId GetOldestMultiXactId | ( | void | ) |
Definition at line 2128 of file multixact.c.
References FirstMultiXactId, i, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactStateData::nextMXact, OldestMemberMXactId, and OldestVisibleMXactId.
Referenced by AddNewRelationTuple(), ExecuteTruncate(), vac_update_datfrozenxid(), and vacuum_set_xid_limits().
{ MultiXactId oldestMXact; MultiXactId nextMXact; int i; /* * This is the oldest valid value among all the OldestMemberMXactId[] and * OldestVisibleMXactId[] entries, or nextMXact if none are valid. */ LWLockAcquire(MultiXactGenLock, LW_SHARED); /* * We have to beware of the possibility that nextMXact is in the * wrapped-around state. We don't fix the counter itself here, but we * must be sure to use a valid value in our calculation. */ nextMXact = MultiXactState->nextMXact; if (nextMXact < FirstMultiXactId) nextMXact = FirstMultiXactId; oldestMXact = nextMXact; for (i = 1; i <= MaxOldestSlot; i++) { MultiXactId thisoldest; thisoldest = OldestMemberMXactId[i]; if (MultiXactIdIsValid(thisoldest) && MultiXactIdPrecedes(thisoldest, oldestMXact)) oldestMXact = thisoldest; thisoldest = OldestVisibleMXactId[i]; if (MultiXactIdIsValid(thisoldest) && MultiXactIdPrecedes(thisoldest, oldestMXact)) oldestMXact = thisoldest; } LWLockRelease(MultiXactGenLock); return oldestMXact; }
void multixact_redo | ( | XLogRecPtr | lsn, | |
XLogRecord * | record | |||
) |
Definition at line 2343 of file multixact.c.
References Assert, elog, i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), xl_multixact_create::members, xl_multixact_create::mid, xl_multixact_create::moff, MultiXactAdvanceNextMXact(), MultiXactMemberControlLock, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, VariableCacheData::nextXid, xl_multixact_create::nmembers, PANIC, RecordNewMultiXact(), ShmemVariableCache, SimpleLruWritePage(), TransactionIdAdvance, TransactionIdFollowsOrEquals(), TransactionIdPrecedes(), MultiXactMember::xid, XidGenLock, XLogRecord::xl_info, XLogRecord::xl_xid, XLOG_MULTIXACT_CREATE_ID, XLOG_MULTIXACT_ZERO_MEM_PAGE, XLOG_MULTIXACT_ZERO_OFF_PAGE, XLogRecGetData, XLR_BKP_BLOCK_MASK, ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().
{ uint8 info = record->xl_info & ~XLR_INFO_MASK; /* Backup blocks are not used in multixact records */ Assert(!(record->xl_info & XLR_BKP_BLOCK_MASK)); if (info == XLOG_MULTIXACT_ZERO_OFF_PAGE) { int pageno; int slotno; memcpy(&pageno, XLogRecGetData(record), sizeof(int)); LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE); slotno = ZeroMultiXactOffsetPage(pageno, false); SimpleLruWritePage(MultiXactOffsetCtl, slotno); Assert(!MultiXactOffsetCtl->shared->page_dirty[slotno]); LWLockRelease(MultiXactOffsetControlLock); } else if (info == XLOG_MULTIXACT_ZERO_MEM_PAGE) { int pageno; int slotno; memcpy(&pageno, XLogRecGetData(record), sizeof(int)); LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE); slotno = ZeroMultiXactMemberPage(pageno, false); SimpleLruWritePage(MultiXactMemberCtl, slotno); Assert(!MultiXactMemberCtl->shared->page_dirty[slotno]); LWLockRelease(MultiXactMemberControlLock); } else if (info == XLOG_MULTIXACT_CREATE_ID) { xl_multixact_create *xlrec = (xl_multixact_create *) XLogRecGetData(record); TransactionId max_xid; int i; /* Store the data back into the SLRU files */ RecordNewMultiXact(xlrec->mid, xlrec->moff, xlrec->nmembers, xlrec->members); /* Make sure nextMXact/nextOffset are beyond what this record has */ MultiXactAdvanceNextMXact(xlrec->mid + 1, xlrec->moff + xlrec->nmembers); /* * Make sure nextXid is beyond any XID mentioned in the record. This * should be unnecessary, since any XID found here ought to have other * evidence in the XLOG, but let's be safe. */ max_xid = record->xl_xid; for (i = 0; i < xlrec->nmembers; i++) { if (TransactionIdPrecedes(max_xid, xlrec->members[i].xid)) max_xid = xlrec->members[i].xid; } /* * We don't expect anyone else to modify nextXid, hence startup * process doesn't need to hold a lock while checking this. We still * acquire the lock to modify it, though. */ if (TransactionIdFollowsOrEquals(max_xid, ShmemVariableCache->nextXid)) { LWLockAcquire(XidGenLock, LW_EXCLUSIVE); ShmemVariableCache->nextXid = max_xid; TransactionIdAdvance(ShmemVariableCache->nextXid); LWLockRelease(XidGenLock); } } else elog(PANIC, "multixact_redo: unknown op code %u", info); }
void multixact_twophase_postabort | ( | TransactionId | xid, | |
uint16 | info, | |||
void * | recdata, | |||
uint32 | len | |||
) |
Definition at line 1582 of file multixact.c.
References multixact_twophase_postcommit().
{ multixact_twophase_postcommit(xid, info, recdata, len); }
void multixact_twophase_postcommit | ( | TransactionId | xid, | |
uint16 | info, | |||
void * | recdata, | |||
uint32 | len | |||
) |
Definition at line 1567 of file multixact.c.
References Assert, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().
Referenced by multixact_twophase_postabort().
{ BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid); Assert(len == sizeof(MultiXactId)); OldestMemberMXactId[dummyBackendId] = InvalidMultiXactId; }
void multixact_twophase_recover | ( | TransactionId | xid, | |
uint16 | info, | |||
void * | recdata, | |||
uint32 | len | |||
) |
Definition at line 1546 of file multixact.c.
References Assert, OldestMemberMXactId, and TwoPhaseGetDummyBackendId().
{ BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid); MultiXactId oldestMember; /* * Get the oldest member XID from the state file record, and set it in the * OldestMemberMXactId slot reserved for this prepared transaction. */ Assert(len == sizeof(MultiXactId)); oldestMember = *((MultiXactId *) recdata); OldestMemberMXactId[dummyBackendId] = oldestMember; }
void MultiXactAdvanceNextMXact | ( | MultiXactId | minMulti, | |
MultiXactOffset | minMultiOffset | |||
) |
Definition at line 2008 of file multixact.c.
References DEBUG2, debug_elog3, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactIdPrecedes(), MultiXactOffsetPrecedes(), MultiXactStateData::nextMXact, and MultiXactStateData::nextOffset.
Referenced by multixact_redo(), and xlog_redo().
{ LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE); if (MultiXactIdPrecedes(MultiXactState->nextMXact, minMulti)) { debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti); MultiXactState->nextMXact = minMulti; } if (MultiXactOffsetPrecedes(MultiXactState->nextOffset, minMultiOffset)) { debug_elog3(DEBUG2, "MultiXact: setting next offset to %u", minMultiOffset); MultiXactState->nextOffset = minMultiOffset; } LWLockRelease(MultiXactGenLock); }
void MultiXactAdvanceOldest | ( | MultiXactId | oldestMulti, | |
Oid | oldestMultiDB | |||
) |
Definition at line 2031 of file multixact.c.
References MultiXactIdPrecedes(), MultiXactStateData::oldestMultiXactId, and SetMultiXactIdLimit().
Referenced by vac_truncate_clog(), and xlog_redo().
{ if (MultiXactIdPrecedes(MultiXactState->oldestMultiXactId, oldestMulti)) SetMultiXactIdLimit(oldestMulti, oldestMultiDB); }
void MultiXactGetCheckptMulti | ( | bool | is_shutdown, | |
MultiXactId * | nextMulti, | |||
MultiXactOffset * | nextMultiOffset, | |||
MultiXactId * | oldestMulti, | |||
Oid * | oldestMultiDB | |||
) |
Definition at line 1825 of file multixact.c.
References DEBUG2, debug_elog6, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, MultiXactStateData::oldestMultiXactDB, and MultiXactStateData::oldestMultiXactId.
Referenced by CreateCheckPoint().
{ LWLockAcquire(MultiXactGenLock, LW_SHARED); *nextMulti = MultiXactState->nextMXact; *nextMultiOffset = MultiXactState->nextOffset; *oldestMulti = MultiXactState->oldestMultiXactId; *oldestMultiDB = MultiXactState->oldestMultiXactDB; LWLockRelease(MultiXactGenLock); debug_elog6(DEBUG2, "MultiXact: checkpoint is nextMulti %u, nextOffset %u, oldestMulti %u in DB %u", *nextMulti, *nextMultiOffset, *oldestMulti, *oldestMultiDB); }
MultiXactId MultiXactIdCreate | ( | TransactionId | xid1, | |
MultiXactStatus | status1, | |||
TransactionId | xid2, | |||
MultiXactStatus | status2 | |||
) |
Definition at line 324 of file multixact.c.
References Assert, AssertArg, CreateMultiXactId(), DEBUG2, debug_elog3, mXactCacheEnt::members, mxid_to_string(), MultiXactMember::status, TransactionIdEquals, TransactionIdIsValid, and MultiXactMember::xid.
Referenced by compute_new_xmax_infomask().
{ MultiXactId newMulti; MultiXactMember members[2]; AssertArg(TransactionIdIsValid(xid1)); AssertArg(TransactionIdIsValid(xid2)); Assert(!TransactionIdEquals(xid1, xid2) || (status1 != status2)); /* * Note: unlike MultiXactIdExpand, we don't bother to check that both XIDs * are still running. In typical usage, xid2 will be our own XID and the * caller just did a check on xid1, so it'd be wasted effort. */ members[0].xid = xid1; members[0].status = status1; members[1].xid = xid2; members[1].status = status2; newMulti = CreateMultiXactId(2, members); debug_elog3(DEBUG2, "Create: %s", mxid_to_string(newMulti, 2, members)); return newMulti; }
MultiXactId MultiXactIdExpand | ( | MultiXactId | multi, | |
TransactionId | xid, | |||
MultiXactStatus | status | |||
) |
Definition at line 374 of file multixact.c.
References AssertArg, CreateMultiXactId(), DEBUG2, debug_elog3, debug_elog4, debug_elog5, GetMultiXactIdMembers(), i, mXactCacheEnt::members, MultiXactIdIsValid, mxstatus_to_string(), mXactCacheEnt::nmembers, palloc(), pfree(), MultiXactMember::status, TransactionIdDidCommit(), TransactionIdEquals, TransactionIdIsInProgress(), TransactionIdIsValid, and MultiXactMember::xid.
Referenced by compute_new_xmax_infomask().
{ MultiXactId newMulti; MultiXactMember *members; MultiXactMember *newMembers; int nmembers; int i; int j; AssertArg(MultiXactIdIsValid(multi)); AssertArg(TransactionIdIsValid(xid)); debug_elog5(DEBUG2, "Expand: received multi %u, xid %u status %s", multi, xid, mxstatus_to_string(status)); /* * Note: we don't allow for old multis here. The reason is that the * only caller of this function does a check that the multixact is * no longer running. */ nmembers = GetMultiXactIdMembers(multi, &members, false); if (nmembers < 0) { MultiXactMember member; /* * The MultiXactId is obsolete. This can only happen if all the * MultiXactId members stop running between the caller checking and * passing it to us. It would be better to return that fact to the * caller, but it would complicate the API and it's unlikely to happen * too often, so just deal with it by creating a singleton MultiXact. */ member.xid = xid; member.status = status; newMulti = CreateMultiXactId(1, &member); debug_elog4(DEBUG2, "Expand: %u has no members, create singleton %u", multi, newMulti); return newMulti; } /* * If the TransactionId is already a member of the MultiXactId with the * same status, just return the existing MultiXactId. */ for (i = 0; i < nmembers; i++) { if (TransactionIdEquals(members[i].xid, xid) && (members[i].status == status)) { debug_elog4(DEBUG2, "Expand: %u is already a member of %u", xid, multi); pfree(members); return multi; } } /* * Determine which of the members of the MultiXactId are still of interest. * This is any running transaction, and also any transaction that grabbed * something stronger than just a lock and was committed. (An update that * aborted is of no interest here.) * * (Removing dead members is just an optimization, but a useful one. * Note we have the same race condition here as above: j could be 0 at the * end of the loop.) */ newMembers = (MultiXactMember *) palloc(sizeof(MultiXactMember) * (nmembers + 1)); for (i = 0, j = 0; i < nmembers; i++) { if (TransactionIdIsInProgress(members[i].xid) || ((members[i].status > MultiXactStatusForUpdate) && TransactionIdDidCommit(members[i].xid))) { newMembers[j].xid = members[i].xid; newMembers[j++].status = members[i].status; } } newMembers[j].xid = xid; newMembers[j++].status = status; newMulti = CreateMultiXactId(j, newMembers); pfree(members); pfree(newMembers); debug_elog3(DEBUG2, "Expand: returning new multi %u", newMulti); return newMulti; }
bool MultiXactIdIsRunning | ( | MultiXactId | multi | ) |
Definition at line 480 of file multixact.c.
References DEBUG2, debug_elog2, debug_elog3, debug_elog4, GetMultiXactIdMembers(), i, mXactCacheEnt::members, mXactCacheEnt::nmembers, pfree(), TransactionIdIsCurrentTransactionId(), and TransactionIdIsInProgress().
Referenced by compute_new_xmax_infomask(), HeapTupleSatisfiesUpdate(), and HeapTupleSatisfiesVacuum().
{ MultiXactMember *members; int nmembers; int i; debug_elog3(DEBUG2, "IsRunning %u?", multi); /* * "false" here means we assume our callers have checked that the given * multi cannot possibly come from a pg_upgraded database. */ nmembers = GetMultiXactIdMembers(multi, &members, false); if (nmembers < 0) { debug_elog2(DEBUG2, "IsRunning: no members"); return false; } /* * Checking for myself is cheap compared to looking in shared memory; * return true if any live subtransaction of the current top-level * transaction is a member. * * This is not needed for correctness, it's just a fast path. */ for (i = 0; i < nmembers; i++) { if (TransactionIdIsCurrentTransactionId(members[i].xid)) { debug_elog3(DEBUG2, "IsRunning: I (%d) am running!", i); pfree(members); return true; } } /* * This could be made faster by having another entry point in procarray.c, * walking the PGPROC array only once for all the members. But in most * cases nmembers should be small enough that it doesn't much matter. */ for (i = 0; i < nmembers; i++) { if (TransactionIdIsInProgress(members[i].xid)) { debug_elog4(DEBUG2, "IsRunning: member %d (%u) is running", i, members[i].xid); pfree(members); return true; } } pfree(members); debug_elog3(DEBUG2, "IsRunning: %u is not running", multi); return false; }
bool MultiXactIdPrecedes | ( | MultiXactId | multi1, | |
MultiXactId | multi2 | |||
) |
Definition at line 2305 of file multixact.c.
Referenced by do_start_worker(), GetMultiXactIdMembers(), GetNewMultiXactId(), GetOldestMultiXactId(), heap_freeze_tuple(), heap_tuple_needs_freeze(), MultiXactAdvanceNextMXact(), MultiXactAdvanceOldest(), MultiXactIdSetOldestVisible(), MultiXactOffsetPagePrecedes(), relation_needs_vacanalyze(), SetMultiXactIdLimit(), TruncateMultiXact(), vac_truncate_clog(), vac_update_datfrozenxid(), and vac_update_relstats().
{ int32 diff = (int32) (multi1 - multi2); return (diff < 0); }
void MultiXactIdSetOldestMember | ( | void | ) |
Definition at line 554 of file multixact.c.
References DEBUG2, debug_elog4, FirstMultiXactId, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactIdIsValid, MyBackendId, MultiXactStateData::nextMXact, and OldestMemberMXactId.
Referenced by heap_delete(), heap_lock_tuple(), heap_lock_updated_tuple(), and heap_update().
{ if (!MultiXactIdIsValid(OldestMemberMXactId[MyBackendId])) { MultiXactId nextMXact; /* * You might think we don't need to acquire a lock here, since * fetching and storing of TransactionIds is probably atomic, but in * fact we do: suppose we pick up nextMXact and then lose the CPU for * a long time. Someone else could advance nextMXact, and then * another someone else could compute an OldestVisibleMXactId that * would be after the value we are going to store when we get control * back. Which would be wrong. */ LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE); /* * We have to beware of the possibility that nextMXact is in the * wrapped-around state. We don't fix the counter itself here, but we * must be sure to store a valid value in our array entry. */ nextMXact = MultiXactState->nextMXact; if (nextMXact < FirstMultiXactId) nextMXact = FirstMultiXactId; OldestMemberMXactId[MyBackendId] = nextMXact; LWLockRelease(MultiXactGenLock); debug_elog4(DEBUG2, "MultiXact: setting OldestMember[%d] = %u", MyBackendId, nextMXact); } }
static void MultiXactIdSetOldestVisible | ( | void | ) | [static] |
Definition at line 606 of file multixact.c.
References DEBUG2, debug_elog4, FirstMultiXactId, i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactIdIsValid, MultiXactIdPrecedes(), MyBackendId, MultiXactStateData::nextMXact, OldestMemberMXactId, and OldestVisibleMXactId.
Referenced by GetMultiXactIdMembers().
{ if (!MultiXactIdIsValid(OldestVisibleMXactId[MyBackendId])) { MultiXactId oldestMXact; int i; LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE); /* * We have to beware of the possibility that nextMXact is in the * wrapped-around state. We don't fix the counter itself here, but we * must be sure to store a valid value in our array entry. */ oldestMXact = MultiXactState->nextMXact; if (oldestMXact < FirstMultiXactId) oldestMXact = FirstMultiXactId; for (i = 1; i <= MaxOldestSlot; i++) { MultiXactId thisoldest = OldestMemberMXactId[i]; if (MultiXactIdIsValid(thisoldest) && MultiXactIdPrecedes(thisoldest, oldestMXact)) oldestMXact = thisoldest; } OldestVisibleMXactId[MyBackendId] = oldestMXact; LWLockRelease(MultiXactGenLock); debug_elog4(DEBUG2, "MultiXact: setting OldestVisible[%d] = %u", MyBackendId, oldestMXact); } }
static bool MultiXactMemberPagePrecedes | ( | int | page1, | |
int | page2 | |||
) | [static] |
Definition at line 2287 of file multixact.c.
References MultiXactOffsetPrecedes().
{ MultiXactOffset offset1; MultiXactOffset offset2; offset1 = ((MultiXactOffset) page1) * MULTIXACT_MEMBERS_PER_PAGE; offset2 = ((MultiXactOffset) page2) * MULTIXACT_MEMBERS_PER_PAGE; return MultiXactOffsetPrecedes(offset1, offset2); }
static bool MultiXactOffsetPagePrecedes | ( | int | page1, | |
int | page2 | |||
) | [static] |
Definition at line 2269 of file multixact.c.
References MultiXactIdPrecedes().
{ MultiXactId multi1; MultiXactId multi2; multi1 = ((MultiXactId) page1) * MULTIXACT_OFFSETS_PER_PAGE; multi1 += FirstMultiXactId; multi2 = ((MultiXactId) page2) * MULTIXACT_OFFSETS_PER_PAGE; multi2 += FirstMultiXactId; return MultiXactIdPrecedes(multi1, multi2); }
static bool MultiXactOffsetPrecedes | ( | MultiXactOffset | offset1, | |
MultiXactOffset | offset2 | |||
) | [static] |
Definition at line 2316 of file multixact.c.
Referenced by MultiXactAdvanceNextMXact(), and MultiXactMemberPagePrecedes().
{ int32 diff = (int32) (offset1 - offset2); return (diff < 0); }
void MultiXactSetNextMXact | ( | MultiXactId | nextMulti, | |
MultiXactOffset | nextMultiOffset | |||
) |
Definition at line 1867 of file multixact.c.
References DEBUG2, debug_elog4, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactStateData::nextMXact, and MultiXactStateData::nextOffset.
Referenced by BootStrapXLOG(), StartupXLOG(), and xlog_redo().
{ debug_elog4(DEBUG2, "MultiXact: setting next multi to %u offset %u", nextMulti, nextMultiOffset); LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE); MultiXactState->nextMXact = nextMulti; MultiXactState->nextOffset = nextMultiOffset; LWLockRelease(MultiXactGenLock); }
void MultiXactShmemInit | ( | void | ) |
Definition at line 1610 of file multixact.c.
References Assert, DEBUG2, debug_elog2, IsUnderPostmaster, MemSet, MultiXactMemberControlLock, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, NUM_MXACTMEMBER_BUFFERS, NUM_MXACTOFFSET_BUFFERS, OldestMemberMXactId, OldestVisibleMXactId, MultiXactStateData::perBackendXactIds, SHARED_MULTIXACT_STATE_SIZE, ShmemInitStruct(), and SimpleLruInit().
Referenced by CreateSharedMemoryAndSemaphores().
{ bool found; debug_elog2(DEBUG2, "Shared Memory Init for MultiXact"); MultiXactOffsetCtl->PagePrecedes = MultiXactOffsetPagePrecedes; MultiXactMemberCtl->PagePrecedes = MultiXactMemberPagePrecedes; SimpleLruInit(MultiXactOffsetCtl, "MultiXactOffset Ctl", NUM_MXACTOFFSET_BUFFERS, 0, MultiXactOffsetControlLock, "pg_multixact/offsets"); SimpleLruInit(MultiXactMemberCtl, "MultiXactMember Ctl", NUM_MXACTMEMBER_BUFFERS, 0, MultiXactMemberControlLock, "pg_multixact/members"); /* Initialize our shared state struct */ MultiXactState = ShmemInitStruct("Shared MultiXact State", SHARED_MULTIXACT_STATE_SIZE, &found); if (!IsUnderPostmaster) { Assert(!found); /* Make sure we zero out the per-backend state */ MemSet(MultiXactState, 0, SHARED_MULTIXACT_STATE_SIZE); } else Assert(found); /* * Set up array pointers. Note that perBackendXactIds[0] is wasted space * since we only use indexes 1..MaxOldestSlot in each array. */ OldestMemberMXactId = MultiXactState->perBackendXactIds; OldestVisibleMXactId = OldestMemberMXactId + MaxOldestSlot; }
Size MultiXactShmemSize | ( | void | ) |
Definition at line 1594 of file multixact.c.
References add_size(), NUM_MXACTMEMBER_BUFFERS, NUM_MXACTOFFSET_BUFFERS, and SimpleLruShmemSize().
Referenced by CreateSharedMemoryAndSemaphores().
{ Size size; #define SHARED_MULTIXACT_STATE_SIZE \ add_size(sizeof(MultiXactStateData), \ mul_size(sizeof(MultiXactId) * 2, MaxOldestSlot)) size = SHARED_MULTIXACT_STATE_SIZE; size = add_size(size, SimpleLruShmemSize(NUM_MXACTOFFSET_BUFFERS, 0)); size = add_size(size, SimpleLruShmemSize(NUM_MXACTMEMBER_BUFFERS, 0)); return size; }
static int mXactCacheGetById | ( | MultiXactId | multi, | |
MultiXactMember ** | members | |||
) | [static] |
Definition at line 1332 of file multixact.c.
References DEBUG2, debug_elog2, debug_elog3, mXactCacheEnt::members, mXactCacheEnt::multi, mxid_to_string(), mXactCacheEnt::next, mXactCacheEnt::nmembers, and palloc().
Referenced by GetMultiXactIdMembers().
{ mXactCacheEnt *entry; debug_elog3(DEBUG2, "CacheGet: looking for %u", multi); for (entry = MXactCache; entry != NULL; entry = entry->next) { if (entry->multi == multi) { MultiXactMember *ptr; Size size; size = sizeof(MultiXactMember) * entry->nmembers; ptr = (MultiXactMember *) palloc(size); *members = ptr; memcpy(ptr, entry->members, size); debug_elog3(DEBUG2, "CacheGet: found %s", mxid_to_string(multi, entry->nmembers, entry->members)); return entry->nmembers; } } debug_elog2(DEBUG2, "CacheGet: not found"); return -1; }
static MultiXactId mXactCacheGetBySet | ( | int | nmembers, | |
MultiXactMember * | members | |||
) | [static] |
Definition at line 1293 of file multixact.c.
References DEBUG2, debug_elog2, debug_elog3, InvalidMultiXactId, mXactCacheEnt::members, memcmp(), mXactCacheEnt::multi, mxactMemberComparator(), mxid_to_string(), mXactCacheEnt::next, mXactCacheEnt::nmembers, and qsort.
Referenced by CreateMultiXactId().
{ mXactCacheEnt *entry; debug_elog3(DEBUG2, "CacheGet: looking for %s", mxid_to_string(InvalidMultiXactId, nmembers, members)); /* sort the array so comparison is easy */ qsort(members, nmembers, sizeof(MultiXactMember), mxactMemberComparator); for (entry = MXactCache; entry != NULL; entry = entry->next) { if (entry->nmembers != nmembers) continue; /* * We assume the cache entries are sorted, and that the unused bits in * "status" are zeroed. */ if (memcmp(members, entry->members, nmembers * sizeof(MultiXactMember)) == 0) { debug_elog3(DEBUG2, "CacheGet: found %u", entry->multi); return entry->multi; } } debug_elog2(DEBUG2, "CacheGet: not found :-("); return InvalidMultiXactId; }
static void mXactCachePut | ( | MultiXactId | multi, | |
int | nmembers, | |||
MultiXactMember * | members | |||
) | [static] |
Definition at line 1366 of file multixact.c.
References ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE, ALLOCSET_SMALL_MINSIZE, AllocSetContextCreate(), DEBUG2, debug_elog2, debug_elog3, mXactCacheEnt::members, MemoryContextAlloc(), mXactCacheEnt::multi, mxactMemberComparator(), mxid_to_string(), mXactCacheEnt::next, mXactCacheEnt::nmembers, NULL, offsetof, qsort, and TopTransactionContext.
Referenced by CreateMultiXactId(), and GetMultiXactIdMembers().
{ mXactCacheEnt *entry; debug_elog3(DEBUG2, "CachePut: storing %s", mxid_to_string(multi, nmembers, members)); if (MXactContext == NULL) { /* The cache only lives as long as the current transaction */ debug_elog2(DEBUG2, "CachePut: initializing memory context"); MXactContext = AllocSetContextCreate(TopTransactionContext, "MultiXact Cache Context", ALLOCSET_SMALL_MINSIZE, ALLOCSET_SMALL_INITSIZE, ALLOCSET_SMALL_MAXSIZE); } entry = (mXactCacheEnt *) MemoryContextAlloc(MXactContext, offsetof(mXactCacheEnt, members) + nmembers * sizeof(MultiXactMember)); entry->multi = multi; entry->nmembers = nmembers; memcpy(entry->members, members, nmembers * sizeof(MultiXactMember)); /* mXactCacheGetBySet assumes the entries are sorted, so sort them */ qsort(entry->members, nmembers, sizeof(MultiXactMember), mxactMemberComparator); entry->next = MXactCache; MXactCache = entry; }
static int mxactMemberComparator | ( | const void * | arg1, | |
const void * | arg2 | |||
) | [static] |
Definition at line 1263 of file multixact.c.
References MultiXactMember::status, and MultiXactMember::xid.
Referenced by mXactCacheGetBySet(), and mXactCachePut().
{ MultiXactMember member1 = *(const MultiXactMember *) arg1; MultiXactMember member2 = *(const MultiXactMember *) arg2; if (member1.xid > member2.xid) return 1; if (member1.xid < member2.xid) return -1; if (member1.status > member2.status) return 1; if (member1.status < member2.status) return -1; return 0; }
char* mxid_to_string | ( | MultiXactId | multi, | |
int | nmembers, | |||
MultiXactMember * | members | |||
) |
Definition at line 1424 of file multixact.c.
References appendStringInfo(), appendStringInfoChar(), buf, StringInfoData::data, i, initStringInfo(), MemoryContextStrdup(), mxstatus_to_string(), NULL, pfree(), status(), and TopMemoryContext.
Referenced by CreateMultiXactId(), GetMultiXactIdMembers(), MultiXactIdCreate(), mXactCacheGetById(), mXactCacheGetBySet(), and mXactCachePut().
{ static char *str = NULL; StringInfoData buf; int i; if (str != NULL) pfree(str); initStringInfo(&buf); appendStringInfo(&buf, "%u %d[%u (%s)", multi, nmembers, members[0].xid, mxstatus_to_string(members[0].status)); for (i = 1; i < nmembers; i++) appendStringInfo(&buf, ", %u (%s)", members[i].xid, mxstatus_to_string(members[i].status)); appendStringInfoChar(&buf, ']'); str = MemoryContextStrdup(TopMemoryContext, buf.data); pfree(buf.data); return str; }
static char * mxstatus_to_string | ( | MultiXactStatus | status | ) | [static] |
Definition at line 1401 of file multixact.c.
References elog, ERROR, MultiXactStatusForKeyShare, MultiXactStatusForNoKeyUpdate, MultiXactStatusForShare, MultiXactStatusForUpdate, MultiXactStatusNoKeyUpdate, and MultiXactStatusUpdate.
Referenced by MultiXactIdExpand(), mxid_to_string(), and pg_get_multixact_members().
{ switch (status) { case MultiXactStatusForKeyShare: return "keysh"; case MultiXactStatusForShare: return "sh"; case MultiXactStatusForNoKeyUpdate: return "fornokeyupd"; case MultiXactStatusForUpdate: return "forupd"; case MultiXactStatusNoKeyUpdate: return "nokeyupd"; case MultiXactStatusUpdate: return "upd"; default: elog(ERROR, "unrecognized multixact status %d", status); return ""; } }
Datum pg_get_multixact_members | ( | PG_FUNCTION_ARGS | ) |
Definition at line 2426 of file multixact.c.
References FuncCallContext::attinmeta, BuildTupleFromCStrings(), CreateTemplateTupleDesc(), ereport, errcode(), errmsg(), ERROR, FirstMultiXactId, GetMultiXactIdMembers(), HeapTupleGetDatum, MemoryContextSwitchTo(), FuncCallContext::multi_call_memory_ctx, mxstatus_to_string(), palloc(), pfree(), PG_GETARG_UINT32, SRF_FIRSTCALL_INIT, SRF_IS_FIRSTCALL, SRF_PERCALL_SETUP, SRF_RETURN_DONE, SRF_RETURN_NEXT, TEXTOID, TupleDescGetAttInMetadata(), TupleDescInitEntry(), FuncCallContext::user_fctx, values, and XIDOID.
{ typedef struct { MultiXactMember *members; int nmembers; int iter; } mxact; MultiXactId mxid = PG_GETARG_UINT32(0); mxact *multi; FuncCallContext *funccxt; if (mxid < FirstMultiXactId) ereport(ERROR, (errcode(ERRCODE_INVALID_PARAMETER_VALUE), errmsg("invalid MultiXactId: %u", mxid))); if (SRF_IS_FIRSTCALL()) { MemoryContext oldcxt; TupleDesc tupdesc; funccxt = SRF_FIRSTCALL_INIT(); oldcxt = MemoryContextSwitchTo(funccxt->multi_call_memory_ctx); multi = palloc(sizeof(mxact)); /* no need to allow for old values here */ multi->nmembers = GetMultiXactIdMembers(mxid, &multi->members, false); multi->iter = 0; tupdesc = CreateTemplateTupleDesc(2, false); TupleDescInitEntry(tupdesc, (AttrNumber) 1, "xid", XIDOID, -1, 0); TupleDescInitEntry(tupdesc, (AttrNumber) 2, "mode", TEXTOID, -1, 0); funccxt->attinmeta = TupleDescGetAttInMetadata(tupdesc); funccxt->user_fctx = multi; MemoryContextSwitchTo(oldcxt); } funccxt = SRF_PERCALL_SETUP(); multi = (mxact *) funccxt->user_fctx; while (multi->iter < multi->nmembers) { HeapTuple tuple; char *values[2]; values[0] = palloc(32); sprintf(values[0], "%u", multi->members[multi->iter].xid); values[1] = mxstatus_to_string(multi->members[multi->iter].status); tuple = BuildTupleFromCStrings(funccxt->attinmeta, values); multi->iter++; pfree(values[0]); SRF_RETURN_NEXT(funccxt, HeapTupleGetDatum(tuple)); } if (multi->nmembers > 0) pfree(multi->members); pfree(multi); SRF_RETURN_DONE(funccxt); }
void PostPrepare_MultiXact | ( | TransactionId | xid | ) |
Definition at line 1497 of file multixact.c.
References LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, MultiXactIdIsValid, MyBackendId, OldestMemberMXactId, OldestVisibleMXactId, and TwoPhaseGetDummyBackendId().
Referenced by PrepareTransaction().
{ MultiXactId myOldestMember; /* * Transfer our OldestMemberMXactId value to the slot reserved for the * prepared transaction. */ myOldestMember = OldestMemberMXactId[MyBackendId]; if (MultiXactIdIsValid(myOldestMember)) { BackendId dummyBackendId = TwoPhaseGetDummyBackendId(xid); /* * Even though storing MultiXactId is atomic, acquire lock to make * sure others see both changes, not just the reset of the slot of the * current backend. Using a volatile pointer might suffice, but this * isn't a hot spot. */ LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE); OldestMemberMXactId[dummyBackendId] = myOldestMember; OldestMemberMXactId[MyBackendId] = InvalidMultiXactId; LWLockRelease(MultiXactGenLock); } /* * We don't need to transfer OldestVisibleMXactId value, because the * transaction is not going to be looking at any more multixacts once it's * prepared. * * We assume that storing a MultiXactId is atomic and so we need not take * MultiXactGenLock to do this. */ OldestVisibleMXactId[MyBackendId] = InvalidMultiXactId; /* * Discard the local MultiXactId cache like in AtEOX_MultiXact */ MXactContext = NULL; MXactCache = NULL; }
MultiXactId ReadNextMultiXactId | ( | void | ) |
Definition at line 647 of file multixact.c.
References FirstMultiXactId, LW_SHARED, LWLockAcquire(), LWLockRelease(), MultiXactGenLock, and MultiXactStateData::nextMXact.
Referenced by ATRewriteTables(), AutoVacWorkerMain(), do_start_worker(), and ExecRefreshMatView().
{ MultiXactId mxid; /* XXX we could presumably do this without a lock. */ LWLockAcquire(MultiXactGenLock, LW_SHARED); mxid = MultiXactState->nextMXact; LWLockRelease(MultiXactGenLock); if (mxid < FirstMultiXactId) mxid = FirstMultiXactId; return mxid; }
static void RecordNewMultiXact | ( | MultiXactId | multi, | |
MultiXactOffset | offset, | |||
int | nmembers, | |||
MultiXactMember * | members | |||
) | [static] |
Definition at line 762 of file multixact.c.
References Assert, i, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactMemberControlLock, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, MultiXactStatusUpdate, MXOffsetToFlagsBitShift, MXOffsetToFlagsOffset, MXOffsetToMemberOffset, MXOffsetToMemberPage, SimpleLruReadPage(), MultiXactMember::status, status(), and MultiXactMember::xid.
Referenced by CreateMultiXactId(), and multixact_redo().
{ int pageno; int prev_pageno; int entryno; int slotno; MultiXactOffset *offptr; int i; LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE); pageno = MultiXactIdToOffsetPage(multi); entryno = MultiXactIdToOffsetEntry(multi); /* * Note: we pass the MultiXactId to SimpleLruReadPage as the "transaction" * to complain about if there's any I/O error. This is kinda bogus, but * since the errors will always give the full pathname, it should be clear * enough that a MultiXactId is really involved. Perhaps someday we'll * take the trouble to generalize the slru.c error reporting code. */ slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi); offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno]; offptr += entryno; *offptr = offset; MultiXactOffsetCtl->shared->page_dirty[slotno] = true; /* Exchange our lock */ LWLockRelease(MultiXactOffsetControlLock); LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE); prev_pageno = -1; for (i = 0; i < nmembers; i++, offset++) { TransactionId *memberptr; uint32 *flagsptr; uint32 flagsval; int bshift; int flagsoff; int memberoff; Assert(members[i].status <= MultiXactStatusUpdate); pageno = MXOffsetToMemberPage(offset); memberoff = MXOffsetToMemberOffset(offset); flagsoff = MXOffsetToFlagsOffset(offset); bshift = MXOffsetToFlagsBitShift(offset); if (pageno != prev_pageno) { slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, multi); prev_pageno = pageno; } memberptr = (TransactionId *) (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff); *memberptr = members[i].xid; flagsptr = (uint32 *) (MultiXactMemberCtl->shared->page_buffer[slotno] + flagsoff); flagsval = *flagsptr; flagsval &= ~(((1 << MXACT_MEMBER_BITS_PER_XACT) - 1) << bshift); flagsval |= (members[i].status << bshift); *flagsptr = flagsval; MultiXactMemberCtl->shared->page_dirty[slotno] = true; } LWLockRelease(MultiXactMemberControlLock); }
void SetMultiXactIdLimit | ( | MultiXactId | oldest_datminmxid, | |
Oid | oldest_datoid | |||
) |
Definition at line 1884 of file multixact.c.
References Assert, DEBUG1, ereport, errhint(), errmsg(), FirstMultiXactId, get_database_name(), InRecovery, IsTransactionState(), IsUnderPostmaster, LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MaxMultiXactId, MultiXactStateData::multiStopLimit, MultiXactStateData::multiVacLimit, MultiXactStateData::multiWarnLimit, MultiXactStateData::multiWrapLimit, MultiXactGenLock, MultiXactIdIsValid, MultiXactIdPrecedes(), MultiXactStateData::nextMXact, MultiXactStateData::oldestMultiXactDB, MultiXactStateData::oldestMultiXactId, PMSIGNAL_START_AUTOVAC_LAUNCHER, SendPostmasterSignal(), and WARNING.
Referenced by BootStrapXLOG(), MultiXactAdvanceOldest(), StartupXLOG(), and xlog_redo().
{ MultiXactId multiVacLimit; MultiXactId multiWarnLimit; MultiXactId multiStopLimit; MultiXactId multiWrapLimit; MultiXactId curMulti; Assert(MultiXactIdIsValid(oldest_datminmxid)); /* * The place where we actually get into deep trouble is halfway around * from the oldest potentially-existing XID/multi. (This calculation is * probably off by one or two counts for Xids, because the special XIDs * reduce the size of the loop a little bit. But we throw in plenty of * slop below, so it doesn't matter.) */ multiWrapLimit = oldest_datminmxid + (MaxMultiXactId >> 1); if (multiWrapLimit < FirstMultiXactId) multiWrapLimit += FirstMultiXactId; /* * We'll refuse to continue assigning MultiXactIds once we get within 100 * multi of data loss. */ multiStopLimit = multiWrapLimit - 100; if (multiStopLimit < FirstMultiXactId) multiStopLimit -= FirstMultiXactId; /* * We'll start complaining loudly when we get within 10M multis of the stop * point. This is kind of arbitrary, but if you let your gas gauge get * down to 1% of full, would you be looking for the next gas station? We * need to be fairly liberal about this number because there are lots of * scenarios where most transactions are done by automatic clients that * won't pay attention to warnings. (No, we're not gonna make this * configurable. If you know enough to configure it, you know enough to * not get in this kind of trouble in the first place.) */ multiWarnLimit = multiStopLimit - 10000000; if (multiWarnLimit < FirstMultiXactId) multiWarnLimit -= FirstMultiXactId; /* * We'll start trying to force autovacuums when oldest_datminmxid gets * to be more than 200 million transactions old. */ multiVacLimit = oldest_datminmxid + 200000000; if (multiVacLimit < FirstMultiXactId) multiVacLimit += FirstMultiXactId; /* Grab lock for just long enough to set the new limit values */ LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE); MultiXactState->oldestMultiXactId = oldest_datminmxid; MultiXactState->oldestMultiXactDB = oldest_datoid; MultiXactState->multiVacLimit = multiVacLimit; MultiXactState->multiWarnLimit = multiWarnLimit; MultiXactState->multiStopLimit = multiStopLimit; MultiXactState->multiWrapLimit = multiWrapLimit; curMulti = MultiXactState->nextMXact; LWLockRelease(MultiXactGenLock); /* Log the info */ ereport(DEBUG1, (errmsg("MultiXactId wrap limit is %u, limited by database with OID %u", multiWrapLimit, oldest_datoid))); /* * If past the autovacuum force point, immediately signal an autovac * request. The reason for this is that autovac only processes one * database per invocation. Once it's finished cleaning up the oldest * database, it'll call here, and we'll signal the postmaster to start * another iteration immediately if there are still any old databases. */ if (MultiXactIdPrecedes(multiVacLimit, curMulti) && IsUnderPostmaster && !InRecovery) SendPostmasterSignal(PMSIGNAL_START_AUTOVAC_LAUNCHER); /* Give an immediate warning if past the wrap warn point */ if (MultiXactIdPrecedes(multiWarnLimit, curMulti) && !InRecovery) { char *oldest_datname; /* * We can be called when not inside a transaction, for example during * StartupXLOG(). In such a case we cannot do database access, so we * must just report the oldest DB's OID. * * Note: it's also possible that get_database_name fails and returns * NULL, for example because the database just got dropped. We'll * still warn, even though the warning might now be unnecessary. */ if (IsTransactionState()) oldest_datname = get_database_name(oldest_datoid); else oldest_datname = NULL; if (oldest_datname) ereport(WARNING, (errmsg("database \"%s\" must be vacuumed before %u more MultiXactIds are used", oldest_datname, multiWrapLimit - curMulti), errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n" "You might also need to commit or roll back old prepared transactions."))); else ereport(WARNING, (errmsg("database with OID %u must be vacuumed before %u more MultiXactIds are used", oldest_datoid, multiWrapLimit - curMulti), errhint("To avoid a database shutdown, execute a database-wide VACUUM in that database.\n" "You might also need to commit or roll back old prepared transactions."))); } }
void ShutdownMultiXact | ( | void | ) |
Definition at line 1812 of file multixact.c.
References MultiXactMemberCtl, MultiXactOffsetCtl, and SimpleLruFlush().
Referenced by ShutdownXLOG().
{ /* Flush dirty MultiXact pages to disk */ TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_START(false); SimpleLruFlush(MultiXactOffsetCtl, false); SimpleLruFlush(MultiXactMemberCtl, false); TRACE_POSTGRESQL_MULTIXACT_CHECKPOINT_DONE(false); }
static bool SlruScanDirCbFindEarliest | ( | SlruCtl | ctl, | |
char * | filename, | |||
int | segpage, | |||
void * | data | |||
) | [static] |
Definition at line 2179 of file multixact.c.
References mxtruncinfo::earliestExistingPage, and SlruCtlData::PagePrecedes.
Referenced by TruncateMultiXact().
{ mxtruncinfo *trunc = (mxtruncinfo *) data; if (trunc->earliestExistingPage == -1 || ctl->PagePrecedes(segpage, trunc->earliestExistingPage)) { trunc->earliestExistingPage = segpage; } return false; /* keep going */ }
void StartupMultiXact | ( | void | ) |
Definition at line 1731 of file multixact.c.
References LW_EXCLUSIVE, LWLockAcquire(), LWLockRelease(), MemSet, mXactCacheEnt::multi, MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactMemberControlLock, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, MXOffsetToFlagsOffset, MXOffsetToMemberOffset, MXOffsetToMemberPage, MultiXactStateData::nextMXact, MultiXactStateData::nextOffset, and SimpleLruReadPage().
Referenced by StartupXLOG().
{ MultiXactId multi = MultiXactState->nextMXact; MultiXactOffset offset = MultiXactState->nextOffset; int pageno; int entryno; int flagsoff; /* Clean up offsets state */ LWLockAcquire(MultiXactOffsetControlLock, LW_EXCLUSIVE); /* * Initialize our idea of the latest page number. */ pageno = MultiXactIdToOffsetPage(multi); MultiXactOffsetCtl->shared->latest_page_number = pageno; /* * Zero out the remainder of the current offsets page. See notes in * StartupCLOG() for motivation. */ entryno = MultiXactIdToOffsetEntry(multi); if (entryno != 0) { int slotno; MultiXactOffset *offptr; slotno = SimpleLruReadPage(MultiXactOffsetCtl, pageno, true, multi); offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno]; offptr += entryno; MemSet(offptr, 0, BLCKSZ - (entryno * sizeof(MultiXactOffset))); MultiXactOffsetCtl->shared->page_dirty[slotno] = true; } LWLockRelease(MultiXactOffsetControlLock); /* And the same for members */ LWLockAcquire(MultiXactMemberControlLock, LW_EXCLUSIVE); /* * Initialize our idea of the latest page number. */ pageno = MXOffsetToMemberPage(offset); MultiXactMemberCtl->shared->latest_page_number = pageno; /* * Zero out the remainder of the current members page. See notes in * TrimCLOG() for motivation. */ flagsoff = MXOffsetToFlagsOffset(offset); if (flagsoff != 0) { int slotno; TransactionId *xidptr; int memberoff; memberoff = MXOffsetToMemberOffset(offset); slotno = SimpleLruReadPage(MultiXactMemberCtl, pageno, true, offset); xidptr = (TransactionId *) (MultiXactMemberCtl->shared->page_buffer[slotno] + memberoff); MemSet(xidptr, 0, BLCKSZ - memberoff); /* * Note: we don't need to zero out the flag bits in the remaining * members of the current group, because they are always reset before * writing. */ MultiXactMemberCtl->shared->page_dirty[slotno] = true; } LWLockRelease(MultiXactMemberControlLock); }
void TruncateMultiXact | ( | MultiXactId | oldestMXact | ) |
Definition at line 2201 of file multixact.c.
References mxtruncinfo::earliestExistingPage, LWLockRelease(), MultiXactIdPrecedes(), MultiXactIdToOffsetEntry, MultiXactIdToOffsetPage, MultiXactMemberCtl, MultiXactOffsetControlLock, MultiXactOffsetCtl, MXOffsetToMemberPage, SimpleLruReadPage_ReadOnly(), SimpleLruTruncate(), SlruScanDirCbFindEarliest(), and SlruScanDirectory().
Referenced by vac_truncate_clog().
{ MultiXactOffset oldestOffset; mxtruncinfo trunc; MultiXactId earliest; /* * Note we can't just plow ahead with the truncation; it's possible that * there are no segments to truncate, which is a problem because we are * going to attempt to read the offsets page to determine where to truncate * the members SLRU. So we first scan the directory to determine the * earliest offsets page number that we can read without error. */ trunc.earliestExistingPage = -1; SlruScanDirectory(MultiXactOffsetCtl, SlruScanDirCbFindEarliest, &trunc); earliest = trunc.earliestExistingPage * MULTIXACT_OFFSETS_PER_PAGE; /* nothing to do */ if (MultiXactIdPrecedes(oldestMXact, earliest)) return; /* * First, compute the safe truncation point for MultiXactMember. * This is the starting offset of the multixact we were passed * as MultiXactOffset cutoff. */ { int pageno; int slotno; int entryno; MultiXactOffset *offptr; /* lock is acquired by SimpleLruReadPage_ReadOnly */ pageno = MultiXactIdToOffsetPage(oldestMXact); entryno = MultiXactIdToOffsetEntry(oldestMXact); slotno = SimpleLruReadPage_ReadOnly(MultiXactOffsetCtl, pageno, oldestMXact); offptr = (MultiXactOffset *) MultiXactOffsetCtl->shared->page_buffer[slotno]; offptr += entryno; oldestOffset = *offptr; LWLockRelease(MultiXactOffsetControlLock); } /* truncate MultiXactOffset */ SimpleLruTruncate(MultiXactOffsetCtl, MultiXactIdToOffsetPage(oldestMXact)); /* truncate MultiXactMembers and we're done */ SimpleLruTruncate(MultiXactMemberCtl, MXOffsetToMemberPage(oldestOffset)); }
static void WriteMZeroPageXlogRec | ( | int | pageno, | |
uint8 | info | |||
) | [static] |
Definition at line 2328 of file multixact.c.
References XLogRecData::buffer, XLogRecData::data, XLogRecData::len, XLogRecData::next, and XLogInsert().
Referenced by ZeroMultiXactMemberPage(), and ZeroMultiXactOffsetPage().
{ XLogRecData rdata; rdata.data = (char *) (&pageno); rdata.len = sizeof(int); rdata.buffer = InvalidBuffer; rdata.next = NULL; (void) XLogInsert(RM_MULTIXACT_ID, info, &rdata); }
static int ZeroMultiXactMemberPage | ( | int | pageno, | |
bool | writeXlog | |||
) | [static] |
Definition at line 1707 of file multixact.c.
References MultiXactMemberCtl, SimpleLruZeroPage(), WriteMZeroPageXlogRec(), and XLOG_MULTIXACT_ZERO_MEM_PAGE.
Referenced by BootStrapMultiXact(), ExtendMultiXactMember(), and multixact_redo().
{ int slotno; slotno = SimpleLruZeroPage(MultiXactMemberCtl, pageno); if (writeXlog) WriteMZeroPageXlogRec(pageno, XLOG_MULTIXACT_ZERO_MEM_PAGE); return slotno; }
static int ZeroMultiXactOffsetPage | ( | int | pageno, | |
bool | writeXlog | |||
) | [static] |
Definition at line 1691 of file multixact.c.
References MultiXactOffsetCtl, SimpleLruZeroPage(), WriteMZeroPageXlogRec(), and XLOG_MULTIXACT_ZERO_OFF_PAGE.
Referenced by BootStrapMultiXact(), ExtendMultiXactOffset(), and multixact_redo().
{ int slotno; slotno = SimpleLruZeroPage(MultiXactOffsetCtl, pageno); if (writeXlog) WriteMZeroPageXlogRec(pageno, XLOG_MULTIXACT_ZERO_OFF_PAGE); return slotno; }
SlruCtlData MultiXactMemberCtlData [static] |
Definition at line 156 of file multixact.c.
SlruCtlData MultiXactOffsetCtlData [static] |
Definition at line 155 of file multixact.c.
MultiXactStateData* MultiXactState [static] |
Definition at line 239 of file multixact.c.
mXactCacheEnt* MXactCache = NULL [static] |
Definition at line 269 of file multixact.c.
MemoryContext MXactContext = NULL [static] |
Definition at line 270 of file multixact.c.
MultiXactId* OldestMemberMXactId [static] |
Definition at line 240 of file multixact.c.
Referenced by AtEOXact_MultiXact(), AtPrepare_MultiXact(), GetNewMultiXactId(), GetOldestMultiXactId(), multixact_twophase_postcommit(), multixact_twophase_recover(), MultiXactIdSetOldestMember(), MultiXactIdSetOldestVisible(), MultiXactShmemInit(), and PostPrepare_MultiXact().
MultiXactId* OldestVisibleMXactId [static] |
Definition at line 241 of file multixact.c.
Referenced by AtEOXact_MultiXact(), GetOldestMultiXactId(), MultiXactIdSetOldestVisible(), MultiXactShmemInit(), and PostPrepare_MultiXact().