Hi hackers,
I found a problem when doing the test shown below:
Time
Session A
Session B
T1
postgres=# create table test(a int);
CREATE TABLE
postgres=# insert into test values (1);
INSERT 0 1
T2
postgres=#
begin;
BEGIN
postgres=*# lock table test in access exclusive mode ;
LOCK
TABLE
T3
postgres=# begin;
BEGIN
postgres=*# lock table test in exclusive mode ;
T4
Case 1:
postgres=*# lock table test in share row exclusive mode nowait;
ERROR: could not obtain lock on relation
"test"
--------------------------------------------
Case 2:
postgres=*# lock table test in share row exclusive mode;
LOCK TABLE
At T4 moment in session A, (case 1) when executing SQL ??lock table test in
share row exclusive mode nowait;??, an error occurs with message ??could not
obtain lock on relation test";However, (case 2) when executing the SQL above
without nowait, lock can be obtained successfully.
Digging into the source code, I find that in case 2 the lock was obtained in
the function ProcSleep instead of LockAcquireExtended. Due to nowait logic
processed before WaitOnLock->ProcSleep, acquiring lock failed in case 1. Can
any changes be made so that the act of such lock granted occurs before
WaitOnLock?
Providing a more universal case:
Transaction A already holds an n-mode lock on table test. If then transaction A
requests an m-mode lock on table Test, m and n have the following constraints:
(lockMethodTable->conflictTab[n] & lockMethodTable->conflictTab[m])
== lockMethodTable->conflictTab[m]
Obviously, in this case, m<=n.
Should the m-mode lock be granted before WaitOnLock?
In the case of m=n (i.e. we already hold the lock), the m-mode lock is
immediately granted in the LocalLock path, without the need of lock conflict
check.
Based on the facts above, can we obtain a weaker lock (m<n) on the same object
within the same transaction without doing lock conflict check?
Since m=n works, m<n should certainly work too.
I am attaching a patch here with which the problem in case 1 fixed.With Regards, Jingxian Li.
v1-0001-LockAcquireExtended-improvement.patch
Description: Binary data
