diff options
author | Noah Misch <noah@leadboat.com> | 2024-06-27 19:21:05 -0700 |
---|---|---|
committer | Noah Misch <noah@leadboat.com> | 2024-06-27 19:21:12 -0700 |
commit | 1a6d65b64e8495280862f5757062eb844d134488 (patch) | |
tree | 41179d764979e856b28b682eeaa0fdb3bdab8216 /src/backend/storage/lmgr | |
parent | c3437fb7255b1ad7b19c9d6149919b60daa9bb1d (diff) |
Lock before setting relhassubclass on RELKIND_PARTITIONED_INDEX.
Commit 5b562644fec696977df4a82790064e8287927891 added a comment that
SetRelationHasSubclass() callers must hold this lock. When commit
17f206fbc824d2b4b14480199ca9ff7dea417eda extended use of this column to
partitioned indexes, it didn't take the lock. As the latter commit
message mentioned, we currently never reset a partitioned index to
relhassubclass=f. That largely avoids harm from the lock omission. The
cause for fixing this now is to unblock introducing a rule about locks
required to heap_update() a pg_class row. This might cause more
deadlocks. It gives minor user-visible benefits:
- If an ALTER INDEX SET TABLESPACE runs concurrently with ALTER TABLE
ATTACH PARTITION or CREATE PARTITION OF, one transaction blocks
instead of failing with "tuple concurrently updated". (Many cases of
DDL concurrency still fail that way.)
- Match ALTER INDEX ATTACH PARTITION in choosing to lock the index.
While not user-visible today, we'll need this if we ever make something
set the flag to false for a partitioned index, like ANALYZE does today
for tables. Back-patch to v12 (all supported versions), the plan for
the commit relying on the new rule. In back branches, add
LockOrStrongerHeldByMe() instead of adding a LockHeldByMe() parameter.
Reviewed (in an earlier version) by Robert Haas.
Discussion: https://postgr.es/m/20240611024525.9f.nmisch@google.com
Diffstat (limited to 'src/backend/storage/lmgr')
-rw-r--r-- | src/backend/storage/lmgr/lmgr.c | 40 | ||||
-rw-r--r-- | src/backend/storage/lmgr/lock.c | 44 |
2 files changed, 56 insertions, 28 deletions
diff --git a/src/backend/storage/lmgr/lmgr.c b/src/backend/storage/lmgr/lmgr.c index d4fa5f6ebc4..79068795af4 100644 --- a/src/backend/storage/lmgr/lmgr.c +++ b/src/backend/storage/lmgr/lmgr.c @@ -307,32 +307,26 @@ CheckRelationLockedByMe(Relation relation, LOCKMODE lockmode, bool orstronger) relation->rd_lockInfo.lockRelId.dbId, relation->rd_lockInfo.lockRelId.relId); - if (LockHeldByMe(&tag, lockmode)) - return true; + return (orstronger ? + LockOrStrongerHeldByMe(&tag, lockmode) : + LockHeldByMe(&tag, lockmode)); +} - if (orstronger) - { - LOCKMODE slockmode; +/* + * CheckRelationOidLockedByMe + * + * Like the above, but takes an OID as argument. + */ +bool +CheckRelationOidLockedByMe(Oid relid, LOCKMODE lockmode, bool orstronger) +{ + LOCKTAG tag; - for (slockmode = lockmode + 1; - slockmode <= MaxLockMode; - slockmode++) - { - if (LockHeldByMe(&tag, slockmode)) - { -#ifdef NOT_USED - /* Sometimes this might be useful for debugging purposes */ - elog(WARNING, "lock mode %s substituted for %s on relation %s", - GetLockmodeName(tag.locktag_lockmethodid, slockmode), - GetLockmodeName(tag.locktag_lockmethodid, lockmode), - RelationGetRelationName(relation)); -#endif - return true; - } - } - } + SetLocktagRelationOid(&tag, relid); - return false; + return (orstronger ? + LockOrStrongerHeldByMe(&tag, lockmode) : + LockHeldByMe(&tag, lockmode)); } /* diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index 31933693d66..bc888d2108d 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -579,11 +579,17 @@ DoLockModesConflict(LOCKMODE mode1, LOCKMODE mode2) } /* - * LockHeldByMe -- test whether lock 'locktag' is held with mode 'lockmode' - * by the current transaction + * LockHeldByMeExtended -- test whether lock 'locktag' is held by the current + * transaction + * + * Returns true if current transaction holds a lock on 'tag' of mode + * 'lockmode'. If 'orstronger' is true, a stronger lockmode is also OK. + * ("Stronger" is defined as "numerically higher", which is a bit + * semantically dubious but is OK for the purposes we use this for.) */ -bool -LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode) +static bool +LockHeldByMeExtended(const LOCKTAG *locktag, + LOCKMODE lockmode, bool orstronger) { LOCALLOCKTAG localtag; LOCALLOCK *locallock; @@ -599,7 +605,35 @@ LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode) (void *) &localtag, HASH_FIND, NULL); - return (locallock && locallock->nLocks > 0); + if (locallock && locallock->nLocks > 0) + return true; + + if (orstronger) + { + LOCKMODE slockmode; + + for (slockmode = lockmode + 1; + slockmode <= MaxLockMode; + slockmode++) + { + if (LockHeldByMeExtended(locktag, slockmode, false)) + return true; + } + } + + return false; +} + +bool +LockHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode) +{ + return LockHeldByMeExtended(locktag, lockmode, false); +} + +bool +LockOrStrongerHeldByMe(const LOCKTAG *locktag, LOCKMODE lockmode) +{ + return LockHeldByMeExtended(locktag, lockmode, true); } #ifdef USE_ASSERT_CHECKING |