我如何找出在 Postgres 数据库中持有 PgLock 咨询锁的是什么?

How can I find out what is holding a PgLock advisory lock in the Postgres database?

我正在使用 pg_lock gem to manage Postgres advisory locks 在进程之间进行协调以避免竞争条件。我有一个锁失败并出现错误 Was unable to aquire a lock "<em>my_lock_name</em>" 在 <em>N[=16= 之后] attempts,这告诉我其他东西已经在锁上了。我如何在底层数据库中查找此锁以了解有关持有它的内容的更多信息?

以下是如何从 PgLock#lock! 调用到数据库中的实际锁以获取有关持有它的内容的更多信息:

  1. 找到 PgLock 用于您的锁名称的锁键。这分为两半(& 0xFFFF_FFFF 是必需的,因为 PgLock 将这些数字作为有符号整数处理,但 Postgres 将它们视为无符号整数):
    • 第一个是2147483648。这只是来自 pg_lock.rb.
    • PG_LOCK_SPACE & 0xFFFF_FFFF
    • 第二个可以通过在下面替换你的锁名来获得:
      PgLock.new(name: '').send(:key, "my_lock_name") & 0xFFFF_FFFF
      
  2. 运行 在 Postgres 中执行此查询以在 pg_locks table 中找到您的密钥,将 objid 替换为您在上面获得的密钥中的密钥:
    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
    
    这将显示有关此密钥上持有的任何活动锁的信息。特别是 pid 列是持有锁的连接的 posgres 服务器 pid。
  3. 您可以从 pg_stat_activity 获得有关持有锁的连接正在做什么的更多信息:
    SELECT * FROM pg_stat_activity WHERE pid = PID;
    
  4. 在极端情况下 你可以终止连接并强制释放锁:
    SELECT pg_terminate_backend(PID);