Re: 8.1.2 locking issues - Mailing list pgsql-general

From Ed L.
Subject Re: 8.1.2 locking issues
Date
Msg-id 200611092212.31024.pgsql@bluepolka.net
Whole thread Raw
In response to Re: 8.1.2 locking issues  (Alvaro Herrera <alvherre@commandprompt.com>)
Responses Re: 8.1.2 locking issues
List pgsql-general
I have a few questions on pgsql locking terms and such...

I created the following view to make viewing the locks
a little easier:

-- CREATE OR REPLACE VIEW locksview AS
-- SELECT l.*, r.*, a.*, now() - a.query_start as query_age,
--        substring(replace(current_query, '\n', ' '), 1, 30) as sql30,
--        case when granted then 'granted' else 'WAITING' end as status,
--        case l.mode when 'AccessShareLock' then 1
--                    when 'RowShareLock' then 2
--                    when 'RowExclusiveLock' then 3
--                    when 'ShareUpdateExclusiveLock' then 4
--                    when 'ShareLock' then 5
--                    when 'ShareRowExclusiveLock' then 6
--                    when 'ExclusiveLock' then 7
--                    when 'AccessExclusiveLock' then 8
--                    else 100 end as exclusivity
-- FROM pg_locks l LEFT OUTER JOIN pg_class r ON r.oid = l.relation
--                 LEFT OUTER JOIN pg_stat_activity a ON l.pid = a.procpid;

I then started two transactions that try to update the
same row, and then ran the following query on the view
above:

SELECT now(), client_addr, pid, query_age, status, locktype, mode,
       relname, page, tuple as tup, current_query
FROM locksview
WHERE now() - query_start > '3 minute'::INTERVAL
ORDER BY query_age DESC, exclusivity DESC;

              now              | client_addr | pid  |    query_age    | status  |   locktype    |       mode       |
relname| page | tup |               current_query                 

-------------------------------+-------------+------+-----------------+---------+---------------+------------------+---------+------+-----+--------------------------------------------
 2006-11-09 20:37:25.680662-08 | 10.0.1.82   | 6484 | 00:01:25.830264 | granted | transactionid | ExclusiveLock    |
    |      |     | <IDLE> in transaction 
 2006-11-09 20:37:25.680662-08 | 10.0.1.82   | 6484 | 00:01:25.830264 | granted | relation      | RowExclusiveLock |
foo    |      |     | <IDLE> in transaction 
 2006-11-09 20:37:25.680662-08 | 10.0.1.82   | 6484 | 00:01:25.830264 | granted | relation      | AccessShareLock  |
foo    |      |     | <IDLE> in transaction 
 2006-11-09 20:37:25.680662-08 | 10.0.1.82   | 6508 | 00:01:18.862623 | granted | tuple         | ExclusiveLock    |
foo    |    0 |   7 | update foo set msg = 'maybe' where id = 3; 
 2006-11-09 20:37:25.680662-08 | 10.0.1.82   | 6508 | 00:01:18.862623 | granted | transactionid | ExclusiveLock    |
    |      |     | update foo set msg = 'maybe' where id = 3; 
 2006-11-09 20:37:25.680662-08 | 10.0.1.82   | 6508 | 00:01:18.862623 | WAITING | transactionid | ShareLock        |
    |      |     | update foo set msg = 'maybe' where id = 3; 
 2006-11-09 20:37:25.680662-08 | 10.0.1.82   | 6508 | 00:01:18.862623 | granted | relation      | RowExclusiveLock |
foo    |      |     | update foo set msg = 'maybe' where id = 3; 
 2006-11-09 20:37:25.680662-08 | 10.0.1.82   | 6508 | 00:01:18.862623 | granted | relation      | AccessShareLock  |
foo    |      |     | update foo set msg = 'maybe' where id = 3; 
(8 rows)


In this case, pid 6484 updated the row first but did not
commit, then 6508 tried to update the same row and naturally
blocked.  I understand at a very basic level why this
would block, so that's not the spirit of my questions.  I
also understand each transaction holds its acquired locks
until the end of its transaction.  But I'd like to better
understand the pg_locks view and pgsql locking terms.

First, I don't see rhyme or reason in the transactionid locks.
Can someone explain why 6508 has a transactionid ExclusiveLock,
but now is waiting on a transactionid ShareLock?  That seems
unintuitive.  It would seem that if you hold a more exclusive
lock, getting a less exclusive lock would not be a problem.  Is
there rhyme or reason for this?  From the docs, I'd guess the
ExclusiveLock is given to block "select for updates" that might
want to grab that row after 6508 already got in line, and that
it is grabbing the ShareLock for... what?

Second, 6508, the *blocked* process, also holds a tuple
ExclusiveLock on the page and tuple of foo on which it is
actually blocked.  Again, is there rhyme or reason I'm missing?

Third, what is it that causes values to show up in the page and
tuple columns?

Finally, both processes, the blocked and the blocking, hold
relation RowExclusiveLocks, which again, hardly seems intuitive.
It would seem that the blocked process would not have that lock
until it actually had access to update the row in question.
The docs do not say RowExclusiveLock conflicts with
RowExclusiveLock, but I guess I'm expecting to to that conflict
since one process is blocking on the other for updating the same
row.

TIA.
Ed

pgsql-general by date:

Previous
From: "Dawid Kuroczko"
Date:
Subject: Re: Remote tables infrastructure.
Next
From: "Hitoshi Harada"
Date:
Subject: Re: AutoVacuum on demand?