diff options
author | Tom Lane <tgl@sss.pgh.pa.us> | 2012-02-06 12:34:10 -0500 |
---|---|---|
committer | Tom Lane <tgl@sss.pgh.pa.us> | 2012-02-06 12:34:10 -0500 |
commit | c6d76d7c82ebebb7210029f7382c0ebe2c558bca (patch) | |
tree | 7182728d71ac5da2d12b5f74d1c8ff983412d08c /src/backend/access/transam/multixact.c | |
parent | 96abd81744a90511b7cae9299e589412ce1897c9 (diff) | |
download | postgresql-c6d76d7c82ebebb7210029f7382c0ebe2c558bca.tar.gz postgresql-c6d76d7c82ebebb7210029f7382c0ebe2c558bca.zip |
Add locking around WAL-replay modification of shared-memory variables.
Originally, most of this code assumed that no Postgres backends could be
running concurrently with it, and so no locking could be needed. That
assumption fails in Hot Standby. While it's still true that Hot Standby
backends should never change values like nextXid, they can examine them,
and consistency is important in some cases such as when computing a
snapshot. Therefore, prudence requires that WAL replay code obtain the
relevant locks when modifying such variables, even though it can examine
them without taking a lock. We were following that coding rule in some
places but not all. This commit applies the coding rule uniformly to all
updates of ShmemVariableCache and MultiXactState fields; a search of the
replay routines did not find any other cases that seemed to be at risk.
In addition, this commit fixes a longstanding thinko in replay of NEXTOID
and checkpoint records: we tried to advance nextOid only if it was behind
the value in the WAL record, but the comparison would draw the wrong
conclusion if OID wraparound had occurred since the previous value.
Better to just unconditionally assign the new value, since OID assignment
shouldn't be happening during replay anyway.
The additional locking seems to be more in the nature of future-proofing
than fixing any live bug, so I am not going to back-patch it. The NEXTOID
fix will be back-patched separately.
Diffstat (limited to 'src/backend/access/transam/multixact.c')
-rw-r--r-- | src/backend/access/transam/multixact.c | 12 |
1 files changed, 9 insertions, 3 deletions
diff --git a/src/backend/access/transam/multixact.c b/src/backend/access/transam/multixact.c index 454ca310f33..0f4cea124d7 100644 --- a/src/backend/access/transam/multixact.c +++ b/src/backend/access/transam/multixact.c @@ -1655,8 +1655,9 @@ CheckPointMultiXact(void) * Set the next-to-be-assigned MultiXactId and offset * * This is used when we can determine the correct next ID/offset exactly - * from a checkpoint record. We need no locking since it is only called - * during bootstrap and XLog replay. + * from a checkpoint record. Although this is only called during bootstrap + * and XLog replay, we take the lock in case any hot-standby backends are + * examining the values. */ void MultiXactSetNextMXact(MultiXactId nextMulti, @@ -1664,8 +1665,10 @@ MultiXactSetNextMXact(MultiXactId nextMulti, { 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); } /* @@ -1674,12 +1677,14 @@ MultiXactSetNextMXact(MultiXactId nextMulti, * * This is used when we can determine minimum safe values from an XLog * record (either an on-line checkpoint or an mxact creation log entry). - * We need no locking since it is only called during XLog replay. + * Although this is only called during XLog replay, we take the lock in case + * any hot-standby backends are examining the values. */ void MultiXactAdvanceNextMXact(MultiXactId minMulti, MultiXactOffset minMultiOffset) { + LWLockAcquire(MultiXactGenLock, LW_EXCLUSIVE); if (MultiXactIdPrecedes(MultiXactState->nextMXact, minMulti)) { debug_elog3(DEBUG2, "MultiXact: setting next multi to %u", minMulti); @@ -1691,6 +1696,7 @@ MultiXactAdvanceNextMXact(MultiXactId minMulti, minMultiOffset); MultiXactState->nextOffset = minMultiOffset; } + LWLockRelease(MultiXactGenLock); } /* |