Как я могу узнать, что удерживает консультативную блокировку PgLock в базе данных Postgres?

#ruby #postgresql #database-locking

#ruby #postgresql #блокировка базы данных

Вопрос:

Я использую драгоценный камень pg_lock для управления консультативными блокировками Postgres для координации между процессами, чтобы избежать условий гонки. У меня есть блокировка, которая выходит из строя с ошибкой about Was unable to aquire a lock "my_lock_name" after N attempts , которая говорит мне, что что-то еще уже удерживает блокировку. Как я могу найти эту блокировку в базовой базе данных, чтобы узнать больше информации о том, что ее удерживает?

Ответ №1:

Вот как перейти от PgLock#lock! вызова к фактической блокировке в базе данных, чтобы получить больше информации о том, что ее удерживает:

  1. Найдите ключи блокировки, которые PgLock использует для вашего имени блокировки. Это происходит в двух половинах ( amp; 0xFFFF_FFFF это необходимо, потому что PgLock работает с этими числами как целые числа со знаком, но Postgres обрабатывает их как неподписанные):
    • Первый из 2147483648 них. Это просто PG_LOCK_SPACE amp; 0xFFFF_FFFF из pg_lock.rb .
    • Вторую блокировку можно получить, заменив ваше имя блокировки в следующем:
       PgLock.new(name: '').send(:key, "my_lock_name") amp; 0xFFFF_FFFF
        
  2. Запустите этот запрос в Postgres, чтобы найти ваш ключ в pg_locks таблице, 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 — это pid сервера posgres для соединения, содержащего блокировку.

  3. Вы можете получить дополнительную информацию о том, что делает соединение, удерживающее блокировку, из pg_stat_activity :
     SELECT * FROM pg_stat_activity WHERE pid = PID;
      
  4. В крайнем случае вы можете разорвать соединение и принудительно снять блокировку с помощью:
     SELECT pg_terminate_backend(PID);