I'm using the pg_lock gem to manage Postgres advisory locks for coordinating between processes to avoid race conditions. I have a lock that is failing with an error about Was unable to aquire a lock "my_lock_name" after N attempts
, which tells me that something else is already holding onto the lock. How can I look up this lock in the underlying database to find out more information about what's holding it?
Asked
Active
Viewed 1,148 times
1

Wolfgang
- 3,470
- 1
- 20
- 36
1 Answers
1
Here’s how to go from a PgLock#lock!
call to the actual lock in the database to get more info about what’s holding it:
- Find the lock keys that PgLock is using for your lock name. This comes in two halves (the
& 0xFFFF_FFFF
is necessary because PgLock works with these numbers as signed ints, but Postgres treats them as unsigned):- The first one is
2147483648
. This is simplyPG_LOCK_SPACE & 0xFFFF_FFFF
from pg_lock.rb. - The second one can be obtained by replacing your lock name in the following:
PgLock.new(name: '').send(:key, "my_lock_name") & 0xFFFF_FFFF
- The first one is
- Run this query in Postgres to find your key in the
pg_locks
table, replacing theobjid
with the one from the key you got above:
This will show information about any active locks being held on this key. In particular the pid column is the posgres server pid of the connection holding the lock.SELECT * FROM pg_locks WHERE locktype = 'advisory' AND classid = 2147483648 AND -- First key, the static PG_LOCK_SPACE one objid = 2928511612 AND -- Second key, based on your lock name objsubid = 2; -- key is int pair, not single bigint
- You can get more information about what the connection holding the lock is doing from
pg_stat_activity
:SELECT * FROM pg_stat_activity WHERE pid = PID;
- In extremis you can terminate the connection and force the lock to release with:
SELECT pg_terminate_backend(PID);

Wolfgang
- 3,470
- 1
- 20
- 36