From: Heikki Linnakangas Date: Mon, 22 Aug 2016 13:05:56 +0000 (+0300) Subject: Get rid of globalXmin tracking. X-Git-Url: http://git.postgresql.org/gitweb/static/gitweb.js?a=commitdiff_plain;h=dd118344ea241baf8a8db71069ea4cc486389192;p=users%2Fheikki%2Fpostgres.git Get rid of globalXmin tracking. --- diff --git a/src/backend/access/heap/heapam.c b/src/backend/access/heap/heapam.c index a01edd75d9..2bd1e37be8 100644 --- a/src/backend/access/heap/heapam.c +++ b/src/backend/access/heap/heapam.c @@ -1995,8 +1995,6 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer, if (all_dead) *all_dead = first_call; - Assert(TransactionIdIsValid(RecentGlobalXmin)); - Assert(ItemPointerGetBlockNumber(tid) == BufferGetBlockNumber(buffer)); offnum = ItemPointerGetOffsetNumber(tid); at_chain_start = first_call; @@ -2092,7 +2090,7 @@ heap_hot_search_buffer(ItemPointer tid, Relation relation, Buffer buffer, * transactions. */ if (all_dead && *all_dead && - !HeapTupleIsSurelyDead(heapTuple, RecentGlobalXmin)) + !HeapTupleIsSurelyDead(heapTuple, GetRecentGlobalXmin())) *all_dead = false; /* @@ -6117,8 +6115,8 @@ heap_abort_speculative(Relation relation, HeapTuple tuple) * RecentGlobalXmin. That's not pretty, but it doesn't seem worth * inventing a nicer API for this. */ - Assert(TransactionIdIsValid(RecentGlobalXmin)); - PageSetPrunable(page, RecentGlobalXmin); + Assert(TransactionIdIsValid(GetRecentGlobalXmin())); + PageSetPrunable(page, GetRecentGlobalXmin()); /* store transaction information of xact deleting the tuple */ tp.t_data->t_infomask &= ~(HEAP_XMAX_BITS | HEAP_MOVED); diff --git a/src/backend/access/heap/pruneheap.c b/src/backend/access/heap/pruneheap.c index 6ff92516ed..e4c18a6a0d 100644 --- a/src/backend/access/heap/pruneheap.c +++ b/src/backend/access/heap/pruneheap.c @@ -23,6 +23,7 @@ #include "miscadmin.h" #include "pgstat.h" #include "storage/bufmgr.h" +#include "storage/procarray.h" #include "utils/snapmgr.h" #include "utils/rel.h" #include "utils/tqual.h" @@ -102,10 +103,10 @@ heap_page_prune_opt(Relation relation, Buffer buffer) */ if (IsCatalogRelation(relation) || RelationIsAccessibleInLogicalDecoding(relation)) - OldestXmin = RecentGlobalXmin; + OldestXmin = GetRecentGlobalXmin(); else OldestXmin = - TransactionIdLimitedForOldSnapshots(RecentGlobalDataXmin, + TransactionIdLimitedForOldSnapshots(GetRecentGlobalDataXmin(), relation); Assert(TransactionIdIsValid(OldestXmin)); diff --git a/src/backend/access/nbtree/nbtpage.c b/src/backend/access/nbtree/nbtpage.c index 2001dc14fb..88e5fdd4ea 100644 --- a/src/backend/access/nbtree/nbtpage.c +++ b/src/backend/access/nbtree/nbtpage.c @@ -30,6 +30,7 @@ #include "storage/indexfsm.h" #include "storage/lmgr.h" #include "storage/predicate.h" +#include "storage/procarray.h" #include "utils/snapmgr.h" static bool _bt_mark_page_halfdead(Relation rel, Buffer buf, BTStack stack); @@ -759,7 +760,7 @@ _bt_page_recyclable(Page page) */ opaque = (BTPageOpaque) PageGetSpecialPointer(page); if (P_ISDELETED(opaque) && - TransactionIdPrecedes(opaque->btpo.xact, RecentGlobalXmin)) + TransactionIdPrecedes(opaque->btpo.xact, GetRecentGlobalXmin())) return true; return false; } diff --git a/src/backend/access/spgist/spgvacuum.c b/src/backend/access/spgist/spgvacuum.c index 15b867f24c..067251e0f2 100644 --- a/src/backend/access/spgist/spgvacuum.c +++ b/src/backend/access/spgist/spgvacuum.c @@ -25,6 +25,7 @@ #include "storage/bufmgr.h" #include "storage/indexfsm.h" #include "storage/lmgr.h" +#include "storage/procarray.h" #include "utils/snapmgr.h" @@ -520,7 +521,7 @@ vacuumRedirectAndPlaceholder(Relation index, Buffer buffer) dt = (SpGistDeadTuple) PageGetItem(page, PageGetItemId(page, i)); if (dt->tupstate == SPGIST_REDIRECT && - TransactionIdPrecedes(dt->xid, RecentGlobalXmin)) + TransactionIdPrecedes(dt->xid, GetRecentGlobalXmin())) { dt->tupstate = SPGIST_PLACEHOLDER; Assert(opaque->nRedirection > 0); diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 308398154c..3b7272c522 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -4827,7 +4827,6 @@ BootStrapXLOG(void) TransactionIdRetreat(latestCompletedXid); pg_atomic_write_u32(&ShmemVariableCache->latestCompletedXid, latestCompletedXid); pg_atomic_write_u32(&ShmemVariableCache->oldestActiveXid, checkPoint.nextXid); - pg_atomic_write_u32(&ShmemVariableCache->globalXmin, checkPoint.nextXid); MultiXactSetNextMXact(checkPoint.nextMulti, checkPoint.nextMultiOffset); SetTransactionIdLimit(checkPoint.oldestXid, checkPoint.oldestXidDB); @@ -6361,7 +6360,6 @@ StartupXLOG(void) TransactionIdRetreat(latestCompletedXid); pg_atomic_write_u32(&ShmemVariableCache->latestCompletedXid, latestCompletedXid); pg_atomic_write_u32(&ShmemVariableCache->oldestActiveXid, checkPoint.nextXid); - pg_atomic_write_u32(&ShmemVariableCache->globalXmin, checkPoint.nextXid); /* * Initialize replication slots, before there's a chance to remove diff --git a/src/backend/storage/ipc/procarray.c b/src/backend/storage/ipc/procarray.c index 570d272911..1744e0b65b 100644 --- a/src/backend/storage/ipc/procarray.c +++ b/src/backend/storage/ipc/procarray.c @@ -72,6 +72,17 @@ static ProcArrayStruct *procArray; static PGPROC *allProcs; static PGXACT *allPgXact; +/* + * Cached values for GetRecentGlobalXmin(). + * + * RecentGlobalXmin and RecentGlobalDataXmin are initialized to + * InvalidTransactionId, to ensure that no one tries to use a stale + * value. Readers should ensure that it has been set to something else + * before using it. + */ +static TransactionId RecentGlobalXmin = InvalidTransactionId; +static TransactionId RecentGlobalDataXmin = InvalidTransactionId; + /* * Bookkeeping for tracking transactions in recovery */ @@ -81,7 +92,6 @@ static TransactionId latestObservedXid = InvalidTransactionId; static LWLockTranche ProcLWLockTranche; static void AdvanceOldestActiveXid(TransactionId myXid); -static void AdvanceGlobalXmin(TransactionId myXmin); /* * Report shared-memory space needed by CreateSharedProcArray. @@ -233,10 +243,8 @@ ProcArrayEndTransaction(PGPROC *proc) { PGXACT *pgxact = &allPgXact[proc->pgprocno]; TransactionId myXid; - TransactionId myXmin; myXid = pgxact->xid; - myXmin = pgxact->xmin; /* A shared lock is enough to modify our own fields */ LWLockAcquire(ProcArrayLock, LW_SHARED); @@ -254,14 +262,20 @@ ProcArrayEndTransaction(PGPROC *proc) /* If we were the oldest active XID, advance oldestXid */ if (TransactionIdIsValid(myXid)) AdvanceOldestActiveXid(myXid); +} + +void +ProcArrayResetXmin(PGPROC *proc) +{ + PGXACT *pgxact = &allPgXact[proc->pgprocno]; /* - * Likewise, if we had the oldest xmin, advance GlobalXmin. (There - * can be multiple transactions with the same xmin, so this - * might be futile.) + * Note we can do this without locking because we assume that storing an Xid + * is atomic. */ - if (TransactionIdIsValid(myXmin)) - AdvanceGlobalXmin(myXmin); + pgxact->xmin = InvalidTransactionId; + + RecentGlobalXmin = InvalidTransactionId; } /* @@ -296,9 +310,6 @@ ProcArrayClearTransaction(PGPROC *proc) /* * We don't need to update oldestActiveXid, because the gxact entry in * the procarray is still running with the same XID. - * - * FIXME: Do we need advance GlobalXmin, though? Does a gxact have a - * valid xmin? */ } @@ -495,8 +506,6 @@ AdvanceOldestActiveXid(TransactionId myXid) TransactionIdGetStatus(xid) != XID_INPROGRESS) TransactionIdAdvance(xid); - Assert(xid >= pg_atomic_read_u32(&ShmemVariableCache->globalXmin)); - if (xid == oldValue) { /* nothing more to do */ @@ -531,22 +540,22 @@ AdvanceOldestActiveXid(TransactionId myXid) } } + + /* - * AdvanceGlobalXmin -- * - * Advance GlobalXmin. */ -static void -AdvanceGlobalXmin(TransactionId myXmin) +TransactionId +GetRecentGlobalXmin(void) { - TransactionId newGlobalXmin; - TransactionId currentGlobalXmin; + TransactionId globalXmin; ProcArrayStruct *arrayP = procArray; int index; + volatile TransactionId replication_slot_xmin = InvalidTransactionId; + volatile TransactionId replication_slot_catalog_xmin = InvalidTransactionId; - /* Quick exit if we were not the oldest xmin */ - if (myXmin != pg_atomic_read_u32(&ShmemVariableCache->globalXmin)) - return; + if (TransactionIdIsValid(RecentGlobalXmin)) + return RecentGlobalXmin; LWLockAcquire(ProcArrayLock, LW_SHARED); @@ -556,8 +565,8 @@ AdvanceGlobalXmin(TransactionId myXmin) * and so protects us against overestimating the result due to future * additions. */ - newGlobalXmin = pg_atomic_read_u32(&ShmemVariableCache->oldestActiveXid); - Assert(TransactionIdIsNormal(newGlobalXmin)); + globalXmin = pg_atomic_read_u32(&ShmemVariableCache->oldestActiveXid); + Assert(TransactionIdIsNormal(globalXmin)); for (index = 0; index < arrayP->numProcs; index++) { @@ -579,8 +588,8 @@ AdvanceGlobalXmin(TransactionId myXmin) /* First consider the transaction's own Xid, if any */ if (TransactionIdIsNormal(xid) && - TransactionIdPrecedes(xid, newGlobalXmin)) - newGlobalXmin = xid; + TransactionIdPrecedes(xid, globalXmin)) + globalXmin = xid; /* * Also consider the transaction's Xmin, if set. @@ -591,22 +600,50 @@ AdvanceGlobalXmin(TransactionId myXmin) */ xid = pgxact->xmin; /* Fetch just once */ if (TransactionIdIsNormal(xid) && - TransactionIdPrecedes(xid, newGlobalXmin)) - newGlobalXmin = xid; + TransactionIdPrecedes(xid, globalXmin)) + globalXmin = xid; } - for (;;) - { - currentGlobalXmin = pg_atomic_read_u32(&ShmemVariableCache->globalXmin); - if (!TransactionIdFollows(newGlobalXmin, currentGlobalXmin)) - break; /* someone else computed a higher value */ - - if (pg_atomic_compare_exchange_u32(&ShmemVariableCache->globalXmin, - ¤tGlobalXmin, newGlobalXmin)) - break; /* we updated the value successfully. */ - } + /* fetch into volatile var while ProcArrayLock is held */ + replication_slot_xmin = procArray->replication_slot_xmin; + replication_slot_catalog_xmin = procArray->replication_slot_catalog_xmin; LWLockRelease(ProcArrayLock); + + /* Update cached variables */ + RecentGlobalXmin = globalXmin - vacuum_defer_cleanup_age; + if (!TransactionIdIsNormal(RecentGlobalXmin)) + RecentGlobalXmin = FirstNormalTransactionId; + + /* Check whether there's a replication slot requiring an older xmin. */ + if (TransactionIdIsValid(replication_slot_xmin) && + NormalTransactionIdPrecedes(replication_slot_xmin, RecentGlobalXmin)) + RecentGlobalXmin = replication_slot_xmin; + + /* Non-catalog tables can be vacuumed if older than this xid */ + RecentGlobalDataXmin = RecentGlobalXmin; + + /* + * Check whether there's a replication slot requiring an older catalog + * xmin. + */ + if (TransactionIdIsNormal(replication_slot_catalog_xmin) && + NormalTransactionIdPrecedes(replication_slot_catalog_xmin, RecentGlobalXmin)) + RecentGlobalXmin = replication_slot_catalog_xmin; + + return RecentGlobalXmin; +} + +TransactionId +GetRecentGlobalDataXmin(void) +{ + if (TransactionIdIsValid(RecentGlobalDataXmin)) + return RecentGlobalDataXmin; + + (void) GetRecentGlobalXmin(); + Assert(TransactionIdIsValid(RecentGlobalDataXmin)); + + return RecentGlobalDataXmin; } /* @@ -869,11 +906,8 @@ GetSnapshotData(Snapshot snapshot) { TransactionId xmin; TransactionId xmax; - TransactionId globalxmin; CommitSeqNo snapshotcsn; bool takenDuringRecovery; - volatile TransactionId replication_slot_xmin = InvalidTransactionId; - volatile TransactionId replication_slot_catalog_xmin = InvalidTransactionId; Assert(snapshot != NULL); @@ -940,36 +974,8 @@ GetSnapshotData(Snapshot snapshot) Assert(TransactionIdIsNormal(xmax)); TransactionIdAdvance(xmax); - /* Also read GlobalXmin. */ - globalxmin = pg_atomic_read_u32(&ShmemVariableCache->globalXmin); - - /* fetch into volatile var while ProcArrayLock is held */ - replication_slot_xmin = procArray->replication_slot_xmin; - replication_slot_catalog_xmin = procArray->replication_slot_catalog_xmin; - LWLockRelease(ProcArrayLock); - /* Update global variables too */ - RecentGlobalXmin = globalxmin - vacuum_defer_cleanup_age; - if (!TransactionIdIsNormal(RecentGlobalXmin)) - RecentGlobalXmin = FirstNormalTransactionId; - - /* Check whether there's a replication slot requiring an older xmin. */ - if (TransactionIdIsValid(replication_slot_xmin) && - NormalTransactionIdPrecedes(replication_slot_xmin, RecentGlobalXmin)) - RecentGlobalXmin = replication_slot_xmin; - - /* Non-catalog tables can be vacuumed if older than this xid */ - RecentGlobalDataXmin = RecentGlobalXmin; - - /* - * Check whether there's a replication slot requiring an older catalog - * xmin. - */ - if (TransactionIdIsNormal(replication_slot_catalog_xmin) && - NormalTransactionIdPrecedes(replication_slot_catalog_xmin, RecentGlobalXmin)) - RecentGlobalXmin = replication_slot_catalog_xmin; - snapshot->xmin = xmin; snapshot->xmax = xmax; snapshot->snapshotcsn = snapshotcsn; diff --git a/src/backend/utils/time/snapmgr.c b/src/backend/utils/time/snapmgr.c index efe9a6b2e1..b4df1067ea 100644 --- a/src/backend/utils/time/snapmgr.c +++ b/src/backend/utils/time/snapmgr.c @@ -156,15 +156,8 @@ static bool CatalogSnapshotStale = true; * These are updated by GetSnapshotData. We initialize them this way, * because even in bootstrap mode, we don't want it to say that * BootstrapTransactionId is in progress. - * - * RecentGlobalXmin and RecentGlobalDataXmin are initialized to - * InvalidTransactionId, to ensure that no one tries to use a stale - * value. Readers should ensure that it has been set to something else - * before using it. */ TransactionId TransactionXmin = FirstNormalTransactionId; -TransactionId RecentGlobalXmin = InvalidTransactionId; -TransactionId RecentGlobalDataXmin = InvalidTransactionId; /* (table, ctid) => (cmin, cmax) mapping during timetravel */ static HTAB *tuplecid_data = NULL; @@ -534,6 +527,8 @@ SetTransactionSnapshot(Snapshot sourcesnap, TransactionId sourcexid, * RecentGlobalXmin. (We could alternatively include those * two variables in exported snapshot files, but it seems better to have * snapshot importers compute reasonably up-to-date values for them.) + * + * FIXME: neither of those reasons hold anymore. Can we drop this? */ CurrentSnapshot = GetSnapshotData(&CurrentSnapshotData); @@ -884,7 +879,7 @@ SnapshotResetXmin(void) if (pairingheap_is_empty(&RegisteredSnapshots)) { - MyPgXact->xmin = InvalidTransactionId; + ProcArrayResetXmin(MyProc); return; } @@ -892,7 +887,7 @@ SnapshotResetXmin(void) pairingheap_first(&RegisteredSnapshots)); if (TransactionIdPrecedes(MyPgXact->xmin, minSnapshot->xmin)) - MyPgXact->xmin = minSnapshot->xmin; + ProcArrayResetXmin(MyProc); } /* diff --git a/src/include/access/mvccvars.h b/src/include/access/mvccvars.h index bfb0800ac7..66d36aca5e 100644 --- a/src/include/access/mvccvars.h +++ b/src/include/access/mvccvars.h @@ -61,16 +61,10 @@ typedef struct VariableCacheData * in-progress. (Or rather, the oldest XID among all still in-progress * transactions; it's not necessarily the one that started first). * Must hold ProcArrayLock in shared mode, and use atomic ops, to update. - * - * globalXmin is the oldest XMIN among all still in-progress transactions. - * Anything older than this is visible to everyone, and can be - * frozen/vacuumed. This does not include lazy VACUUM transactions. Must - * hold ProcArrayLock in shared mode, and use atomic ops to update. */ pg_atomic_uint64 nextCommitSeqNo; pg_atomic_uint32 latestCompletedXid; pg_atomic_uint32 oldestActiveXid; - pg_atomic_uint32 globalXmin; /* * These fields are protected by CommitTsLock diff --git a/src/include/storage/procarray.h b/src/include/storage/procarray.h index d57a2ba9ee..98ef8b0cda 100644 --- a/src/include/storage/procarray.h +++ b/src/include/storage/procarray.h @@ -27,6 +27,7 @@ extern void ProcArrayRemove(PGPROC *proc); extern void ProcArrayEndTransaction(PGPROC *proc); extern void ProcArrayClearTransaction(PGPROC *proc); +extern void ProcArrayResetXmin(PGPROC *proc); extern void ProcArrayInitRecovery(TransactionId oldestActiveXID, TransactionId initializedUptoXID); extern void ProcArrayApplyRecoveryInfo(RunningTransactions running); @@ -44,6 +45,8 @@ extern bool ProcArrayInstallRestoredXmin(TransactionId xmin, PGPROC *proc); extern RunningTransactions GetRunningTransactionData(void); extern bool TransactionIdIsActive(TransactionId xid); +extern TransactionId GetRecentGlobalXmin(void); +extern TransactionId GetRecentGlobalDataXmin(void); extern TransactionId GetOldestXmin(Relation rel, bool ignoreVacuum); extern TransactionId GetOldestActiveTransactionId(void); extern TransactionId GetOldestSafeDecodingTransactionId(void); diff --git a/src/include/utils/snapmgr.h b/src/include/utils/snapmgr.h index 637e38fcf4..2b168f3276 100644 --- a/src/include/utils/snapmgr.h +++ b/src/include/utils/snapmgr.h @@ -57,8 +57,6 @@ extern int64 GetOldSnapshotThresholdTimestamp(void); extern bool FirstSnapshotSet; extern TransactionId TransactionXmin; -extern TransactionId RecentGlobalXmin; -extern TransactionId RecentGlobalDataXmin; extern Snapshot GetTransactionSnapshot(void); extern Snapshot GetLatestSnapshot(void);