Hello, thank you for your review.

Alexander Korotkov писал 2018-06-20 20:54:
Thinking about that more I found that adding vacuum mark as an extra
argument to LockAcquireExtended is also wrong.  It would be still hard
to determine if we should log the lock in LogStandbySnapshot().  We'll
have to add that flag to shared memory table of locks.  And that looks
like a kludge.

Therefore, I'd like to propose another approach: introduce new lock
level.  So, AccessExclusiveLock will be split into two
AccessExclusiveLocalLock and AccessExclusiveLock.  In spite of
AccessExclusiveLock, AccessExclusiveLocalLock will be not logged to
standby, and used for heap truncation.

I expect some resistance to my proposal, because fixing this "small
bug" doesn't deserve new lock level.  But current behavior of
hot_standby_feedback is buggy.  From user prospective,
hot_standby_feedback option is just non-worker, which causes master to
bloat without protection for standby queries from cancel.  We need to
fix that, but I don't see other proper way to do that except adding
new lock level...

Your offer is very interesting, it made patch smaller and more beautiful. So I update patch and made changes accordance with the proposed concept of
special AccessExclusiveLocalLock.

I don't yet understand what is the problem here and why this patch
should solve that.  As I get idea of this patch, GetOldestXmin() will
initialize xmin of walsender with lowest xmin of replication slot.
But xmin of replication slots will be anyway taken into account by
GetSnapshotData() called by vacuum.

How to test:
Make async replica, turn on feedback, reduce max_standby_streaming_delay
and aggressive autovacuum.

You forgot to mention, that one should setup the replication using
replication slot.  Naturally, if replication slot isn't exist, then
master shouldn't keep dead tuples for disconnected standby.  Because
master doesn't know if standby will reconnect or is it gone forever.

I tried to solve hot_standby_feedback without replication slots,
so I found a little window of possibility of case, when vacuum on
master make heap truncation of pages that standby needs for just started
transaction.

How to test:
Make async replica, turn on feedback and reduce
max_standby_streaming_delay.
Make autovacuum more aggressive.
autovacuum = on
autovacuum_max_workers = 1
autovacuum_naptime = 1s
autovacuum_vacuum_threshold = 1
autovacuum_vacuum_cost_delay = 0



Test1:
Here we will do a load on the master and simulation of  a long
transaction with repeated 1 second SEQSCANS on the replica (by  calling
pg_sleep 1 second duration every 6 seconds).
MASTER        REPLICA
     hot_standby = on
     max_standby_streaming_delay = 1s
     hot_standby_feedback = on
start
CREATE TABLE test AS (SELECT id, 1 AS value
FROM generate_series(1,1) id);
pgbench -T600 -P2 -n --file=master.sql postgres
(update test set value = value;)
     start
     BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;
     SELECT pg_sleep(value) FROM test;
     \watch 6



---Autovacuum truncate pages at the end
Result on replica:
FATAL: terminating connection due to conflict with recovery
DETAIL: User was holding a relation lock for too long.



On Patched version lazy_vacuum_truncation passed without fatal errors.



Only some times Error occurs because this tests is too synthetic
ERROR: canceling statement due to conflict with recovery
DETAIL: User was holding shared buffer pin for too long.
Because of rising ResolveRecoveryConflictWithSnapshot while
redo some visibility flags to avoid this conflict we can do test2 or
increase max_standby_streaming_delay.



Test2:
Here we will do a load on the master and simulation of  a long
transaction on the replica (by  taking LOCK on table)
MASTER        REPLICA
     hot_standby = on
     max_standby_streaming_delay = 1s
     hot_standby_feedback = on
start
CREATE TABLE test AS (SELECT id, 1 AS value FROM generate_series(1,1)
id);
pgbench -T600 -P2 -n --file=master.sql postgres
(update test set value = value;)
     start
     BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;
     LOCK TABLE test IN ACCESS SHARE MODE;
     select * from test;
     \watch 6



---Autovacuum truncate pages at the end
Result on replica:
FATAL: terminating connection due to conflict with recovery
DETAIL: User was holding a relation lock for too long.

On Patched version lazy_vacuum_truncation passed without fatal errors.

I would like to here you opinion over this implementation.

--
Ivan Kartyshov
Postgres Professional: http://www.postgrespro.com
The Russian Postgres Company
diff --git a/doc/src/sgml/mvcc.sgml b/doc/src/sgml/mvcc.sgml
index 73934e5..73975cc 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
        </term>
        <listitem>
         <para>
-         Conflicts with the <literal>ACCESS EXCLUSIVE</literal> lock
-         mode only.
+         Conflicts with the <literal>ACCESS EXCLUSIVE</literal> and
+         <literal>ACCESS EXCLUSIVE LOCAL</literal> lock modes.
         </para>
 
         <para>
@@ -872,8 +872,8 @@ ERROR:  could not serialize access due to read/write dependencies among transact
        </term>
        <listitem>
         <para>
-         Conflicts with the <literal>EXCLUSIVE</literal> and
-         <literal>ACCESS EXCLUSIVE</literal> lock modes.
+         Conflicts with the <literal>EXCLUSIVE</literal>, <literal>ACCESS EXCLUSIVE</literal>
+         and <literal>ACCESS EXCLUSIVE LOCAL</literal> lock modes.
         </para>
 
         <para>
@@ -894,8 +894,8 @@ ERROR:  could not serialize access due to read/write dependencies among transact
        <listitem>
         <para>
          Conflicts with the <literal>SHARE</literal>, <literal>SHARE ROW
-         EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
-         <literal>ACCESS EXCLUSIVE</literal> lock modes.
+         EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, <literal>ACCESS EXCLUSIVE</literal>
+         and <literal>ACCESS EXCLUSIVE LOCAL</literal>  lock modes.
         </para>
 
         <para>
@@ -917,8 +917,8 @@ ERROR:  could not serialize access due to read/write dependencies among transact
         <para>
          Conflicts with the <literal>SHARE UPDATE EXCLUSIVE</literal>,
          <literal>SHARE</literal>, <literal>SHARE ROW
-         EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
-         <literal>ACCESS EXCLUSIVE</literal> lock modes.
+         EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, <literal>ACCESS EXCLUSIVE</literal>
+         and <literal>ACCESS EXCLUSIVE LOCAL</literal>  lock modes.
          This mode protects a table against
          concurrent schema changes and <command>VACUUM</command> runs.
         </para>
@@ -942,8 +942,9 @@ ERROR:  could not serialize access due to read/write dependencies among transact
         <para>
          Conflicts with the <literal>ROW EXCLUSIVE</literal>,
          <literal>SHARE UPDATE EXCLUSIVE</literal>, <literal>SHARE ROW
-         EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
-         <literal>ACCESS EXCLUSIVE</literal> lock modes.
+         EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>,
+         <literal>ACCESS EXCLUSIVE</literal> and <literal>ACCESS EXCLUSIVE LOCAL</literal>
+         lock modes.
          This mode protects a table against concurrent data changes.
         </para>
 
@@ -963,8 +964,8 @@ ERROR:  could not serialize access due to read/write dependencies among transact
          Conflicts with the <literal>ROW EXCLUSIVE</literal>,
          <literal>SHARE UPDATE EXCLUSIVE</literal>,
          <literal>SHARE</literal>, <literal>SHARE ROW
-         EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
-         <literal>ACCESS EXCLUSIVE</literal> lock modes.
+         EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, <literal>ACCESS EXCLUSIVE</literal>
+         and <literal>ACCESS EXCLUSIVE LOCAL</literal>  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.
         </para>
@@ -985,8 +986,8 @@ ERROR:  could not serialize access due to read/write dependencies among transact
          Conflicts with the <literal>ROW SHARE</literal>, <literal>ROW
          EXCLUSIVE</literal>, <literal>SHARE UPDATE
          EXCLUSIVE</literal>, <literal>SHARE</literal>, <literal>SHARE
-         ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
-         <literal>ACCESS EXCLUSIVE</literal> lock modes.
+         ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, <literal>ACCESS EXCLUSIVE</literal>
+         and <literal>ACCESS EXCLUSIVE LOCAL</literal>  lock modes.
          This mode allows only concurrent <literal>ACCESS SHARE</literal> locks,
          i.e., only reads from the table can proceed in parallel with a
          transaction holding this lock mode.
@@ -1008,8 +1009,8 @@ ERROR:  could not serialize access due to read/write dependencies among transact
          SHARE</literal>, <literal>ROW SHARE</literal>, <literal>ROW
          EXCLUSIVE</literal>, <literal>SHARE UPDATE
          EXCLUSIVE</literal>, <literal>SHARE</literal>, <literal>SHARE
-         ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, and
-         <literal>ACCESS EXCLUSIVE</literal>).
+         ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, <literal>ACCESS EXCLUSIVE</literal>
+         and <literal>ACCESS EXCLUSIVE LOCAL</literal> ).
          This mode guarantees that the
          holder is the only transaction accessing the table in any way.
         </para>
@@ -1029,6 +1030,32 @@ ERROR:  could not serialize access due to read/write dependencies among transact
       </varlistentry>
      </variablelist>
 
+      <varlistentry>
+       <term>
+        <literal>ACCESS EXCLUSIVE LOCAL</literal>
+       </term>
+       <listitem>
+        <para>
+         Conflicts with locks of all modes (<literal>ACCESS
+         SHARE</literal>, <literal>ROW SHARE</literal>, <literal>ROW
+         EXCLUSIVE</literal>, <literal>SHARE UPDATE
+         EXCLUSIVE</literal>, <literal>SHARE</literal>, <literal>SHARE
+         ROW EXCLUSIVE</literal>, <literal>EXCLUSIVE</literal>, <literal>ACCESS EXCLUSIVE</literal>
+         and <literal>ACCESS EXCLUSIVE LOCAL</literal> ).
+         This mode guarantees that the
+         holder is the only transaction accessing the table in any way.
+        </para>
+
+        <para>
+         Acquired by the <command>VACUUM</command> and autovacuum workers on truncating table.
+         Almost similar as <literal>ACCESS EXCLUSIVE</literal> but don`t generate wal record
+         about lock for standby.
+        </para>
+       </listitem>
+      </varlistentry>
+     </variablelist>
+
+
      <tip>
       <para>
        Only an <literal>ACCESS EXCLUSIVE</literal> lock blocks a
@@ -1069,6 +1096,7 @@ ERROR:  could not serialize access due to read/write dependencies among transact
         <entry>SHARE ROW EXCLUSIVE</entry>
         <entry>EXCLUSIVE</entry>
         <entry>ACCESS EXCLUSIVE</entry>
+        <entry>ACCESS EXCLUSIVE LOCAL</entry>
        </row>
       </thead>
       <tbody>
@@ -1082,6 +1110,7 @@ ERROR:  could not serialize access due to read/write dependencies among transact
         <entry align="center"></entry>
         <entry align="center"></entry>
         <entry align="center">X</entry>
+        <entry align="center">X</entry>
        </row>
        <row>
         <entry>ROW SHARE</entry>
@@ -1093,6 +1122,7 @@ ERROR:  could not serialize access due to read/write dependencies among transact
         <entry align="center"></entry>
         <entry align="center">X</entry>
         <entry align="center">X</entry>
+        <entry align="center">X</entry>
        </row>
        <row>
         <entry>ROW EXCLUSIVE</entry>
@@ -1104,6 +1134,7 @@ ERROR:  could not serialize access due to read/write dependencies among transact
         <entry align="center">X</entry>
         <entry align="center">X</entry>
         <entry align="center">X</entry>
+        <entry align="center">X</entry>
        </row>
        <row>
         <entry>SHARE UPDATE EXCLUSIVE</entry>
@@ -1115,6 +1146,7 @@ ERROR:  could not serialize access due to read/write dependencies among transact
         <entry align="center">X</entry>
         <entry align="center">X</entry>
         <entry align="center">X</entry>
+        <entry align="center">X</entry>
        </row>
        <row>
         <entry>SHARE</entry>
@@ -1126,6 +1158,7 @@ ERROR:  could not serialize access due to read/write dependencies among transact
         <entry align="center">X</entry>
         <entry align="center">X</entry>
         <entry align="center">X</entry>
+        <entry align="center">X</entry>
        </row>
        <row>
         <entry>SHARE ROW EXCLUSIVE</entry>
@@ -1137,6 +1170,7 @@ ERROR:  could not serialize access due to read/write dependencies among transact
         <entry align="center">X</entry>
         <entry align="center">X</entry>
         <entry align="center">X</entry>
+        <entry align="center">X</entry>
        </row>
        <row>
         <entry>EXCLUSIVE</entry>
@@ -1148,6 +1182,7 @@ ERROR:  could not serialize access due to read/write dependencies among transact
         <entry align="center">X</entry>
         <entry align="center">X</entry>
         <entry align="center">X</entry>
+        <entry align="center">X</entry>
        </row>
        <row>
         <entry>ACCESS EXCLUSIVE</entry>
@@ -1159,6 +1194,19 @@ ERROR:  could not serialize access due to read/write dependencies among transact
         <entry align="center">X</entry>
         <entry align="center">X</entry>
         <entry align="center">X</entry>
+        <entry align="center">X</entry>
+       </row>
+       <row>
+        <entry>ACCESS EXCLUSIVE LOCAL</entry>
+        <entry align="center">X</entry>
+        <entry align="center">X</entry>
+        <entry align="center">X</entry>
+        <entry align="center">X</entry>
+        <entry align="center">X</entry>
+        <entry align="center">X</entry>
+        <entry align="center">X</entry>
+        <entry align="center">X</entry>
+        <entry align="center">X</entry>
        </row>
       </tbody>
      </tgroup>
diff --git a/doc/src/sgml/ref/lock.sgml b/doc/src/sgml/ref/lock.sgml
index a225cea..7d1e1e5 100644
--- a/doc/src/sgml/ref/lock.sgml
+++ b/doc/src/sgml/ref/lock.sgml
@@ -26,7 +26,7 @@ LOCK [ TABLE ] [ ONLY ] <replaceable class="parameter">name</replaceable> [ * ]
 <phrase>where <replaceable class="parameter">lockmode</replaceable> is one of:</phrase>
 
     ACCESS SHARE | ROW SHARE | ROW EXCLUSIVE | SHARE UPDATE EXCLUSIVE
-    | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE
+    | SHARE | SHARE ROW EXCLUSIVE | EXCLUSIVE | ACCESS EXCLUSIVE | ACCESS EXCLUSIVE LOCAL
 </synopsis>
  </refsynopsisdiv>
 
@@ -253,8 +253,8 @@ COMMIT WORK;
 
   <para>
    Except for <literal>ACCESS SHARE</literal>, <literal>ACCESS EXCLUSIVE</literal>,
-   and <literal>SHARE UPDATE EXCLUSIVE</literal> lock modes, the
-   <productname>PostgreSQL</productname> lock modes and the
+   <literal>ACCESS EXCLUSIVE LOCAL</literal>, and <literal>SHARE UPDATE EXCLUSIVE</literal>
+   lock modes, the <productname>PostgreSQL</productname> lock modes and the
    <command>LOCK TABLE</command> syntax are compatible with those
    present in <productname>Oracle</productname>.
   </para>
diff --git a/src/backend/commands/vacuumlazy.c b/src/backend/commands/vacuumlazy.c
index 5649a70..c5bd47e 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 87f5e95..6e45183 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -11028,6 +11028,7 @@ lock_type:	ACCESS SHARE					{ $$ = AccessShareLock; }
 			| SHARE ROW EXCLUSIVE			{ $$ = ShareRowExclusiveLock; }
 			| EXCLUSIVE						{ $$ = ExclusiveLock; }
 			| ACCESS EXCLUSIVE				{ $$ = AccessExclusiveLock; }
+			| ACCESS EXCLUSIVE LOCAL		{ $$ = AccessExclusiveLocalLock; }
 		;
 
 opt_nowait:	NOWAIT							{ $$ = true; }
diff --git a/src/backend/storage/lmgr/lock.c b/src/backend/storage/lmgr/lock.c
index dc3d8d9..e157da1 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(AccessExclusiveLock),
+	LOCKBIT_ON(AccessExclusiveLock) |
+	LOCKBIT_ON(AccessExclusiveLocalLock),
 
 	/* RowShareLock */
-	LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock),
+	LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock) |
+	LOCKBIT_ON(AccessExclusiveLocalLock),
 
 	/* RowExclusiveLock */
 	LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) |
-	LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock),
+	LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock) |
+	LOCKBIT_ON(AccessExclusiveLocalLock),
 
 	/* ShareUpdateExclusiveLock */
 	LOCKBIT_ON(ShareUpdateExclusiveLock) |
 	LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) |
-	LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock),
+	LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock) |
+	LOCKBIT_ON(AccessExclusiveLocalLock),
 
 	/* ShareLock */
 	LOCKBIT_ON(RowExclusiveLock) | LOCKBIT_ON(ShareUpdateExclusiveLock) |
 	LOCKBIT_ON(ShareRowExclusiveLock) |
-	LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock),
+	LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock) |
+	LOCKBIT_ON(AccessExclusiveLocalLock),
 
 	/* ShareRowExclusiveLock */
 	LOCKBIT_ON(RowExclusiveLock) | LOCKBIT_ON(ShareUpdateExclusiveLock) |
 	LOCKBIT_ON(ShareLock) | LOCKBIT_ON(ShareRowExclusiveLock) |
-	LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock),
+	LOCKBIT_ON(ExclusiveLock) | LOCKBIT_ON(AccessExclusiveLock) |
+	LOCKBIT_ON(AccessExclusiveLocalLock),
 
 	/* 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(AccessExclusiveLock) |
+	LOCKBIT_ON(AccessExclusiveLocalLock),
 
 	/* 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(AccessExclusiveLock) |
+	LOCKBIT_ON(AccessExclusiveLocalLock),
 
+	/* AccessExclusiveLocalLock */
+	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(AccessExclusiveLocalLock)
 };
 
 /* Names of lock modes, for debug printouts */
@@ -115,7 +129,8 @@ static const char *const lock_mode_names[] =
 	"ShareLock",
 	"ShareRowExclusiveLock",
 	"ExclusiveLock",
-	"AccessExclusiveLock"
+	"AccessExclusiveLock",
+	"AccessExclusiveLocalLock"
 };
 
 #ifndef LOCK_DEBUG
@@ -123,7 +138,7 @@ static bool Dummy_trace = false;
 #endif
 
 static const LockMethodData default_lockmethod = {
-	AccessExclusiveLock,		/* highest valid lock mode number */
+	AccessExclusiveLocalLock,		/* highest valid lock mode number */
 	LockConflicts,
 	lock_mode_names,
 #ifdef LOCK_DEBUG
@@ -134,7 +149,7 @@ static const LockMethodData default_lockmethod = {
 };
 
 static const LockMethodData user_lockmethod = {
-	AccessExclusiveLock,		/* highest valid lock mode number */
+	AccessExclusiveLocalLock,		/* highest valid lock mode number */
 	LockConflicts,
 	lock_mode_names,
 #ifdef LOCK_DEBUG
@@ -810,7 +825,7 @@ LockAcquireExtended(const LOCKTAG *locktag,
 	 * transactions can acquire in a standby server. Make sure this definition
 	 * matches the one in GetRunningTransactionLocks().
 	 */
-	if (lockmode >= AccessExclusiveLock &&
+	if (lockmode == AccessExclusiveLock &&
 		locktag->locktag_type == LOCKTAG_RELATION &&
 		!RecoveryInProgress() &&
 		XLogStandbyInfoActive())
diff --git a/src/include/storage/lock.h b/src/include/storage/lock.h
index 777da71..fcac726 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 72eca39..793e5cd 100644
--- a/src/include/storage/lockdefs.h
+++ b/src/include/storage/lockdefs.h
@@ -44,6 +44,8 @@ typedef int LOCKMODE;
 #define ExclusiveLock			7	/* blocks ROW SHARE/SELECT...FOR UPDATE */
 #define AccessExclusiveLock		8	/* ALTER TABLE, DROP TABLE, VACUUM FULL,
 									 * and unqualified LOCK TABLE */
+#define AccessExclusiveLocalLock 9  /* VACUUM, VACUUM FULL, autovacuum and unqualified
+									 * LOCK TABLE (will not be send to standby) */
 
 typedef struct xl_standby_lock
 {
diff --git a/src/test/regress/expected/lock.out b/src/test/regress/expected/lock.out
index 185fd2f..26b02cb 100644
--- a/src/test/regress/expected/lock.out
+++ b/src/test/regress/expected/lock.out
@@ -25,6 +25,7 @@ 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 MODE;
+LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE LOCAL MODE;
 ROLLBACK;
 -- Try using NOWAIT along with valid options.
 BEGIN TRANSACTION;
@@ -36,6 +37,7 @@ 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 MODE NOWAIT;
+LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE LOCAL MODE NOWAIT;
 ROLLBACK;
 -- Verify that we can lock views.
 BEGIN TRANSACTION;
diff --git a/src/test/regress/sql/lock.sql b/src/test/regress/sql/lock.sql
index 26a7e59..e16cad0 100644
--- a/src/test/regress/sql/lock.sql
+++ b/src/test/regress/sql/lock.sql
@@ -27,6 +27,7 @@ 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 MODE;
+LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE LOCAL MODE;
 ROLLBACK;
 
 -- Try using NOWAIT along with valid options.
@@ -39,6 +40,7 @@ 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 MODE NOWAIT;
+LOCK TABLE lock_tbl1 IN ACCESS EXCLUSIVE LOCAL MODE NOWAIT;
 ROLLBACK;
 
 -- Verify that we can lock views.

Reply via email to