diff --git a/doc/src/sgml/mvcc.sgml b/doc/src/sgml/mvcc.sgml index 73934e5cf37..256811ccdee 100644 --- a/doc/src/sgml/mvcc.sgml +++ b/doc/src/sgml/mvcc.sgml @@ -854,8 +854,8 @@ ERROR: could not serialize access due to read/write dependencies among transact - Conflicts with the ACCESS EXCLUSIVE lock - mode only. + Conflicts with the ACCESS EXCLUSIVE LOCAL and + ACCESS EXCLUSIVE lock modes. @@ -872,8 +872,9 @@ ERROR: could not serialize access due to read/write dependencies among transact - Conflicts with the EXCLUSIVE and - ACCESS EXCLUSIVE lock modes. + Conflicts with the EXCLUSIVE, ACCESS + EXCLUSIVE LOCAL and ACCESS EXCLUSIVE + lock modes. @@ -894,8 +895,9 @@ ERROR: could not serialize access due to read/write dependencies among transact Conflicts with the SHARE, SHARE ROW - EXCLUSIVE, EXCLUSIVE, and - ACCESS EXCLUSIVE lock modes. + EXCLUSIVE, EXCLUSIVE, ACCESS + EXCLUSIVE LOCAL and ACCESS EXCLUSIVE + lock modes. @@ -917,8 +919,9 @@ ERROR: could not serialize access due to read/write dependencies among transact Conflicts with the SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW - EXCLUSIVE, EXCLUSIVE, and - ACCESS EXCLUSIVE lock modes. + EXCLUSIVE, EXCLUSIVE, ACCESS + EXCLUSIVE LOCAL and ACCESS EXCLUSIVE + lock modes. This mode protects a table against concurrent schema changes and VACUUM runs. @@ -942,8 +945,9 @@ ERROR: could not serialize access due to read/write dependencies among transact Conflicts with the ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE ROW - EXCLUSIVE, EXCLUSIVE, and - ACCESS EXCLUSIVE lock modes. + EXCLUSIVE, EXCLUSIVE, + ACCESS EXCLUSIVE and ACCESS EXCLUSIVE + LOCAL lock modes. This mode protects a table against concurrent data changes. @@ -963,8 +967,9 @@ ERROR: could not serialize access due to read/write dependencies among transact Conflicts with the ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE ROW - EXCLUSIVE, EXCLUSIVE, and - ACCESS EXCLUSIVE lock modes. + EXCLUSIVE, EXCLUSIVE, ACCESS + EXCLUSIVE LOCAL and ACCESS EXCLUSIVE + lock modes. This mode protects a table against concurrent data changes, and is self-exclusive so that only one session can hold it at a time. @@ -985,8 +990,9 @@ ERROR: could not serialize access due to read/write dependencies among transact Conflicts with the ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE - ROW EXCLUSIVE, EXCLUSIVE, and - ACCESS EXCLUSIVE lock modes. + ROW EXCLUSIVE, EXCLUSIVE, ACCESS + EXCLUSIVE LOCAL and ACCESS EXCLUSIVE + lock modes. This mode allows only concurrent ACCESS SHARE locks, i.e., only reads from the table can proceed in parallel with a transaction holding this lock mode. @@ -998,6 +1004,31 @@ ERROR: could not serialize access due to read/write dependencies among transact + + + ACCESS EXCLUSIVE LOCAL + + + + Conflicts with locks of all modes (ACCESS + SHARE, ROW SHARE, ROW + EXCLUSIVE, SHARE UPDATE + EXCLUSIVE, SHARE, SHARE + ROW EXCLUSIVE, EXCLUSIVE, ACCESS + EXCLUSIVE LOCAL and ACCESS EXCLUSIVE). + This mode guarantees that the + holder is the only transaction accessing the table in any way. + + + + Acquired by the VACUUM and autovacuum workers on + shortening of table heap. Similar to ACCESS EXCLUSIVE, + but doesn't generate WAL record, because standby can perform heap + shortening with lower lock level. + + + + ACCESS EXCLUSIVE @@ -1008,8 +1039,8 @@ ERROR: could not serialize access due to read/write dependencies among transact SHARE, ROW SHARE, ROW EXCLUSIVE, SHARE UPDATE EXCLUSIVE, SHARE, SHARE - ROW EXCLUSIVE, EXCLUSIVE, and - ACCESS EXCLUSIVE). + ROW EXCLUSIVE, EXCLUSIVE, ACCESS + EXCLUSIVE LOCAL and ACCESS EXCLUSIVE). This mode guarantees that the holder is the only transaction accessing the table in any way. @@ -1029,9 +1060,11 @@ ERROR: could not serialize access due to read/write dependencies among transact + - Only an ACCESS EXCLUSIVE lock blocks a + Only ACCESS EXCLUSIVE LOCAL and + ACCESS EXCLUSIVE locks block a SELECT (without ) statement. @@ -1068,6 +1101,7 @@ ERROR: could not serialize access due to read/write dependencies among transact SHARE SHARE ROW EXCLUSIVE EXCLUSIVE + ACCESS EXCLUSIVE LOCAL ACCESS EXCLUSIVE @@ -1082,6 +1116,7 @@ ERROR: could not serialize access due to read/write dependencies among transact X + X ROW SHARE @@ -1093,6 +1128,7 @@ ERROR: could not serialize access due to read/write dependencies among transact X X + X ROW EXCLUSIVE @@ -1104,6 +1140,7 @@ ERROR: could not serialize access due to read/write dependencies among transact X X X + X SHARE UPDATE EXCLUSIVE @@ -1115,6 +1152,7 @@ ERROR: could not serialize access due to read/write dependencies among transact X X X + X SHARE @@ -1126,6 +1164,7 @@ ERROR: could not serialize access due to read/write dependencies among transact X X X + X SHARE ROW EXCLUSIVE @@ -1137,6 +1176,7 @@ ERROR: could not serialize access due to read/write dependencies among transact X X X + X EXCLUSIVE @@ -1148,6 +1188,19 @@ ERROR: could not serialize access due to read/write dependencies among transact X X X + X + + + ACCESS EXCLUSIVE LOCAL + X + X + X + X + X + X + X + X + X ACCESS EXCLUSIVE @@ -1159,6 +1212,7 @@ ERROR: could not serialize access due to read/write dependencies among transact X X X + X diff --git a/doc/src/sgml/ref/lock.sgml b/doc/src/sgml/ref/lock.sgml index a225cea63b2..74943fe31e0 100644 --- a/doc/src/sgml/ref/lock.sgml +++ b/doc/src/sgml/ref/lock.sgml @@ -26,7 +26,8 @@ LOCK [ TABLE ] [ ONLY ] name [ * ] where lockmode is one of: ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE - | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE + | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE LOCAL + | ACCESS EXCLUSIVE @@ -253,8 +254,8 @@ COMMIT WORK; Except for ACCESS SHARE, ACCESS EXCLUSIVE, - and SHARE UPDATE EXCLUSIVE lock modes, the - PostgreSQL lock modes and the + ACCESS EXCLUSIVE LOCAL, and SHARE UPDATE EXCLUSIVE + lock modes, the PostgreSQL lock modes and the LOCK TABLE syntax are compatible with those present in Oracle. diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c index 5649a70800d..c5bd47eae31 100644 --- a/src/backend/commands/vacuumlazy.c +++ b/src/backend/commands/vacuumlazy.c @@ -1834,7 +1834,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats) lock_retry = 0; while (true) { - if (ConditionalLockRelation(onerel, AccessExclusiveLock)) + if (ConditionalLockRelation(onerel, AccessExclusiveLocalLock)) break; /* @@ -1875,7 +1875,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats) * numbers alone amounts to assuming that the new pages have the * same tuple density as existing ones, which is less unlikely. */ - UnlockRelation(onerel, AccessExclusiveLock); + UnlockRelation(onerel, AccessExclusiveLocalLock); return; } @@ -1890,7 +1890,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats) if (new_rel_pages >= old_rel_pages) { /* can't do anything after all */ - UnlockRelation(onerel, AccessExclusiveLock); + UnlockRelation(onerel, AccessExclusiveLocalLock); return; } @@ -1906,7 +1906,7 @@ lazy_truncate_heap(Relation onerel, LVRelStats *vacrelstats) * that should happen as part of standard invalidation processing once * they acquire lock on the relation. */ - UnlockRelation(onerel, AccessExclusiveLock); + UnlockRelation(onerel, AccessExclusiveLocalLock); /* * Update statistics. Here, it *is* correct to adjust rel_pages @@ -1962,7 +1962,7 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) /* * Check if another process requests a lock on our relation. We are - * holding an AccessExclusiveLock here, so they will be waiting. We + * holding an AccessExclusiveLocalLock here, so they will be waiting. We * only do this once per VACUUM_TRUNCATE_LOCK_CHECK_INTERVAL, and we * only check if that interval has elapsed once every 32 blocks to * keep the number of system calls and actual shared lock table @@ -1979,7 +1979,7 @@ count_nondeletable_pages(Relation onerel, LVRelStats *vacrelstats) if ((INSTR_TIME_GET_MICROSEC(elapsed) / 1000) >= VACUUM_TRUNCATE_LOCK_CHECK_INTERVAL) { - if (LockHasWaitersRelation(onerel, AccessExclusiveLock)) + if (LockHasWaitersRelation(onerel, AccessExclusiveLocalLock)) { ereport(elevel, (errmsg("\"%s\": suspending truncate due to conflicting lock request", diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y index 87f5e958276..7cb76da144c 100644 --- a/src/backend/parser/gram.y +++ b/src/backend/parser/gram.y @@ -11027,6 +11027,7 @@ lock_type: ACCESS SHARE { $$ = AccessShareLock; } | SHARE { $$ = ShareLock; } | SHARE ROW EXCLUSIVE { $$ = ShareRowExclusiveLock; } | EXCLUSIVE { $$ = ExclusiveLock; } + | ACCESS EXCLUSIVE LOCAL { $$ = AccessExclusiveLocalLock; } | ACCESS EXCLUSIVE { $$ = AccessExclusiveLock; } ; diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c index dc3d8d98179..893dad7fe8f 100644 --- a/src/backend/storage/lmgr/lock.c +++ b/src/backend/storage/lmgr/lock.c @@ -66,42 +66,56 @@ static const LOCKMASK LockConflicts[] = { 0, /* AccessShareLock */ + LOCKBIT_ON(AccessExclusiveLocalLock) | LOCKBIT_ON(AccessExclusiveLock), /* RowShareLock */ - LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock), + LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLocalLock) | + LOCKBIT_ON(AccessExclusiveLock), /* RowExclusiveLock */ LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) | - LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock), + LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLocalLock) | + LOCKBIT_ON(AccessExclusiveLock), /* ShareUpdateExclusiveLock */ LOCKBIT_ON(ShareUpdateExclusiveLock) | LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) | - LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock), + LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLocalLock) | + LOCKBIT_ON(AccessExclusiveLock), /* ShareLock */ LOCKBIT_ON(RowExclusiveLock) | LOCKBIT_ON(ShareUpdateExclusiveLock) | LOCKBIT_ON(ShareRowExclusiveLock) | - LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock), + LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLocalLock) | + LOCKBIT_ON(AccessExclusiveLock), /* ShareRowExclusiveLock */ LOCKBIT_ON(RowExclusiveLock) | LOCKBIT_ON(ShareUpdateExclusiveLock) | LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) | - LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock), + LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLocalLock) | + LOCKBIT_ON(AccessExclusiveLock), /* ExclusiveLock */ LOCKBIT_ON(RowShareLock) | LOCKBIT_ON(RowExclusiveLock) | LOCKBIT_ON(ShareUpdateExclusiveLock) | LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) | - LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock), + LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLocalLock) | + LOCKBIT_ON(AccessExclusiveLock), + + /* AccessExclusiveLocalLock */ + LOCKBIT_ON(AccessShareLock) | LOCKBIT_ON(RowShareLock) | + LOCKBIT_ON(RowExclusiveLock) | LOCKBIT_ON(ShareUpdateExclusiveLock) | + LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) | + LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLocalLock) | + LOCKBIT_ON(AccessExclusiveLock), /* AccessExclusiveLock */ LOCKBIT_ON(AccessShareLock) | LOCKBIT_ON(RowShareLock) | LOCKBIT_ON(RowExclusiveLock) | LOCKBIT_ON(ShareUpdateExclusiveLock) | LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) | - LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock) - + LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLocalLock) | + LOCKBIT_ON(AccessExclusiveLock) }; /* Names of lock modes, for debug printouts */ @@ -115,6 +129,7 @@ static const char *const lock_mode_names[] = "ShareLock", "ShareRowExclusiveLock", "ExclusiveLock", + "AccessExclusiveLocalLock", "AccessExclusiveLock" }; diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h index 777da716790..fcac726d1c7 100644 --- a/src/include/storage/lock.h +++ b/src/include/storage/lock.h @@ -82,7 +82,7 @@ typedef struct (vxid).localTransactionId = (proc).lxid) /* MAX_LOCKMODES cannot be larger than the # of bits in LOCKMASK */ -#define MAX_LOCKMODES 10 +#define MAX_LOCKMODES 11 #define LOCKBIT_ON(lockmode) (1 << (lockmode)) #define LOCKBIT_OFF(lockmode) (~(1 << (lockmode))) diff --git a/src/include/storage/lockdefs.h b/src/include/storage/lockdefs.h index 72eca39f17f..eab5f68ef37 100644 --- a/src/include/storage/lockdefs.h +++ b/src/include/storage/lockdefs.h @@ -42,7 +42,8 @@ typedef int LOCKMODE; #define ShareRowExclusiveLock 6 /* like EXCLUSIVE MODE, but allows ROW * SHARE */ #define ExclusiveLock 7 /* blocks ROW SHARE/SELECT...FOR UPDATE */ -#define AccessExclusiveLock 8 /* ALTER TABLE, DROP TABLE, VACUUM FULL, +#define AccessExclusiveLocalLock 8 /* heap truncation by VACUUM */ +#define AccessExclusiveLock 9 /* ALTER TABLE, DROP TABLE, VACUUM FULL, * and unqualified LOCK TABLE */ typedef struct xl_standby_lock diff --git a/src/test/regress/expected/lock.out b/src/test/regress/expected/lock.out index 185fd2f879b..962af126875 100644 --- a/src/test/regress/expected/lock.out +++ b/src/test/regress/expected/lock.out @@ -24,6 +24,7 @@ LOCK TABLE lock_tbl1 IN SHARE UPDATE EXCLUSIVE MODE; LOCK TABLE lock_tbl1 IN SHARE MODE; LOCK lock_tbl1 IN SHARE ROW EXCLUSIVE MODE; LOCK TABLE lock_tbl1 IN EXCLUSIVE MODE; +LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE LOCAL MODE; LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE MODE; ROLLBACK; -- Try using NOWAIT along with valid options. @@ -35,6 +36,7 @@ LOCK TABLE lock_tbl1 IN SHARE UPDATE EXCLUSIVE MODE NOWAIT; LOCK TABLE lock_tbl1 IN SHARE MODE NOWAIT; LOCK TABLE lock_tbl1 IN SHARE ROW EXCLUSIVE MODE NOWAIT; LOCK TABLE lock_tbl1 IN EXCLUSIVE MODE NOWAIT; +LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE LOCAL MODE NOWAIT; LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE MODE NOWAIT; ROLLBACK; -- Verify that we can lock views. diff --git a/src/test/regress/sql/lock.sql b/src/test/regress/sql/lock.sql index 26a7e59a136..2355e26d802 100644 --- a/src/test/regress/sql/lock.sql +++ b/src/test/regress/sql/lock.sql @@ -26,6 +26,7 @@ LOCK TABLE lock_tbl1 IN SHARE UPDATE EXCLUSIVE MODE; LOCK TABLE lock_tbl1 IN SHARE MODE; LOCK lock_tbl1 IN SHARE ROW EXCLUSIVE MODE; LOCK TABLE lock_tbl1 IN EXCLUSIVE MODE; +LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE LOCAL MODE; LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE MODE; ROLLBACK; @@ -38,6 +39,7 @@ LOCK TABLE lock_tbl1 IN SHARE UPDATE EXCLUSIVE MODE NOWAIT; LOCK TABLE lock_tbl1 IN SHARE MODE NOWAIT; LOCK TABLE lock_tbl1 IN SHARE ROW EXCLUSIVE MODE NOWAIT; LOCK TABLE lock_tbl1 IN EXCLUSIVE MODE NOWAIT; +LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE LOCAL MODE NOWAIT; LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE MODE NOWAIT; ROLLBACK;