Гость
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / ExclusiveLock - норма? / 11 сообщений из 11, страница 1 из 1
12.10.2017, 18:59
    #39535619
acidophilus
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ExclusiveLock - норма?
Добрый вечер.


Смотрю в:

[SRC sql]SELECT relation::regclass,* FROM pg_locks[/SR0C]


вижу несколько сессий с "ExclusiveLock" и locktype "virtualxid".



Насколько понял, это "подготовленные транзакции".


Скажите, это нормально они все "ExclusiveLock" создают?

И как понять какой объект БД они блокируют?
...
Рейтинг: 0 / 0
12.10.2017, 19:11
    #39535622
vyegorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ExclusiveLock - норма?
acidophilus,

Это нормально, читайте про типы локов: https://www.postgresql.org/docs/current/static/explicit-locking.html

Объекты все есть в представлении в виде ID.
Т.к. это глобальное представление, то увидеть названия таблиц можно только подключившись к соответствующей базе.
...
Рейтинг: 0 / 0
12.10.2017, 19:14
    #39535624
acidophilus
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ExclusiveLock - норма?
vyegorovacidophilus,

Это нормально, читайте про типы локов: https://www.postgresql.org/docs/current/static/explicit-locking.html

Объекты все есть в представлении в виде ID.
Т.к. это глобальное представление, то увидеть названия таблиц можно только подключившись к соответствующей базе.

Спасибо, почитаю.

Но id у них пустой.
...
Рейтинг: 0 / 0
12.10.2017, 20:14
    #39535658
vyegorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ExclusiveLock - норма?
acidophilus,

Есть там ID:
Код: plaintext
1.
locktype=virtualxid
virtualxid=54/1642395
...
Рейтинг: 0 / 0
23.11.2017, 13:22
    #39558210
acidophilus
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ExclusiveLock - норма?
vyegorovacidophilus,

Есть там ID:
Код: plaintext
1.
locktype=virtualxid
virtualxid=54/1642395



А как найти что это за объект БД?


Например, получаю virtualxid
"121/100324"

А SELECT 100324::oid::regclass ни в одной БД не выводит название таблицы.
...
Рейтинг: 0 / 0
23.11.2017, 13:55
    #39558250
vyegorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ExclusiveLock - норма?
acidophilus,

virtualxid — это идентификатор виртуальной транзакции, а не объект в базе.
Для объекта будет не-NULL-увым поле `relation`.
...
Рейтинг: 0 / 0
23.11.2017, 14:22
    #39558283
acidophilus
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ExclusiveLock - норма?
vyegorovacidophilus,

virtualxid — это идентификатор виртуальной транзакции, а не объект в базе.
Для объекта будет не-NULL-увым поле `relation`.

Подскажите пожалуйста, как понять что блокируется?

Просто в БД висят десятки таких сессий
...
Рейтинг: 0 / 0
23.11.2017, 14:30
    #39558292
vyegorov
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ExclusiveLock - норма?
acidophilus,

Рекурсивный запрос в конце поста: http://blog.postgresql-consulting.com/2017/10/deep-dive-into-postgres-stats.html
...
Рейтинг: 0 / 0
23.11.2017, 14:38
    #39558307
acidophilus
Гость
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ExclusiveLock - норма?
vyegorovacidophilus,

Рекурсивный запрос в конце поста: http://blog.postgresql-consulting.com/2017/10/deep-dive-into-postgres-stats.html


Спасибо.




Однако, ничего не выводит запрос:


Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
WITH RECURSIVE l AS (
  SELECT pid, locktype, mode, granted,
 ROW(locktype,database,relation,page,tuple,virtualxid,transactionid,classid,objid,objsubid) obj
  FROM pg_locks
), pairs AS (
  SELECT w.pid waiter, l.pid locker, l.obj, l.mode
  FROM l w
  JOIN l ON l.obj IS NOT DISTINCT FROM w.obj AND l.locktype=w.locktype AND NOT l.pid=w.pid AND l.granted
  WHERE NOT w.granted
), tree AS (
  SELECT l.locker pid, l.locker root, NULL::record obj, NULL AS mode, 0 lvl, locker::text path, array_agg(l.locker) OVER () all_pids
  FROM ( SELECT DISTINCT locker FROM pairs l WHERE NOT EXISTS (SELECT 1 FROM pairs WHERE waiter=l.locker) ) l
  UNION ALL
  SELECT w.waiter pid, tree.root, w.obj, w.mode, tree.lvl+1, tree.path||'.'||w.waiter, all_pids || array_agg(w.waiter) OVER ()
  FROM tree JOIN pairs w ON tree.pid=w.locker AND NOT w.waiter = ANY ( all_pids )
)
SELECT (clock_timestamp() - a.xact_start)::interval(3) AS ts_age,
       replace(a.state, 'idle in transaction', 'idletx') state,
       (clock_timestamp() - state_change)::interval(3) AS change_age,
       a.datname,tree.pid,a.usename,a.client_addr,lvl,
       (SELECT count(*) FROM tree p WHERE p.path ~ ('^'||tree.path) AND NOT p.path=tree.path) blocked,
       repeat(' .', lvl)||' '||left(regexp_replace(query, '\s+', ' ', 'g'),100) query
FROM tree
JOIN pg_stat_activity a USING (pid)
ORDER BY path;
...
Рейтинг: 0 / 0
23.11.2017, 14:59
    #39558329
Павел Лузанов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ExclusiveLock - норма?
acidophilusА как найти что это за объект БД?


Например, получаю virtualxid
"121/100324"

А SELECT 100324::oid::regclass ни в одной БД не выводит название таблицы.

Строки с locktype=virtualxid ничего не блокируют.
Каждый раз когда начинается транзакция, в pg_locks добавляется эта строчка и удаляется по завершении транзакции.
Строка нужна для того, чтобы другие транзакции знали что эта транзакция еще живая и не завершена.

Хотя документация говорит, что другие транзакции всё-таки могут за неё цепляться:
"На протяжении транзакции серверный процесс удерживает исключительную блокировку виртуального идентификатора транзакции. Если транзакции назначается постоянный идентификатор (что обычно происходит, только если транзакция изменяет состояние базы данных), он также удерживает до её завершения блокировку этого постоянного идентификатора. Когда процесс находит необходимым ожидать именно какую-то другую транзакцию, он делает это, запрашивая разделяемую блокировку для идентификатора этой транзакции ( виртуального или постоянного, в зависимости от ситуации ). Этот запрос будет выполнен, только когда другая транзакция завершится и освободит свои блокировки."
...
Рейтинг: 0 / 0
01.12.2017, 16:59
    #39562708
Павел Лузанов
Участник
Скрыть профиль Поместить в игнор-лист Сообщения автора в теме
ExclusiveLock - норма?
Оставлю здесь, вдруг еще пригодится.

Захотелось всё-таки разобраться зачем в pg_locks создаются строки с locktype=virtualxid.
Что это за ситуации, когда транзакция еще не получившая "настоящий" номер (т.е. только читающая) может кого-то заблокировать.

Вот что нашлось в исходниках :
"Every transaction takes a lock on its own virtual transaction ID. Currently, the only operations that wait for these locks are CREATE INDEX CONCURRENTLY and Hot Standby (in the case of a conflict), so most VXID locks are taken and released by the owner without anyone else needing to care."

Теперь идем в документацию на CREATE INDEX и читаем как выполняется CREATE INDEX CONCURRENTLY:
"При параллельном построении индекса он попадает в системный каталог в одной транзакции, затем ещё два сканирования таблицы выполняются в двух других транзакциях. Перед каждым сканированием таблицы процедура построения индекса должна ждать завершения текущих транзакций, модифицировавших эту таблицу. После второго сканирования также необходимо дожидаться завершения всех транзакций, получивших снимок (см. Главу 13) перед вторым сканированием ."

Вот оно что. Теперь можно и тестовый пример сделать.
В первой транзакции с уровнем изоляции REPEATABLE READ (чтобы снимок подольше оставался) прочитаем строки из таблицы. А во второй после этого попытаемся создать индекс.

Первый сеанс:
Код: sql
1.
2.
3.
4.
5.
6.
7.
postgres=# begin isolation level repeatable read ;
BEGIN
postgres=# select * from t;
 id 
----
  1
(1 row)


Второй сеанс:
Код: sql
1.
postgres=# create index CONCURRENTLY t_idx on t(id);


И второй сеанс повисает.


Теперь смотрим из третьего сеанса на блокировки:
Код: plaintext
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
postgres=# select pid, locktype, virtualxid, granted, relation::regclass, mode
 from pg_locks
 where pid <> pg_backend_pid() order by pid;
 pid  |  locktype  | virtualxid | granted | relation |           mode           
------+------------+------------+---------+----------+--------------------------
 4185 | relation   |            | t       | t        | AccessShareLock
  4185 | virtualxid | 3/177      | t       |          | ExclusiveLock 
 6794 | relation   |            | t       | t_idx    | RowExclusiveLock
 6794 | virtualxid | 4/255      | t       |          | ExclusiveLock
  6794 | virtualxid | 3/177      | f       |          | ShareLock 
 6794 | relation   |            | t       | t        | ShareUpdateExclusiveLock
(6 rows)
Действительно, 5 строка "зацепилась" за вторую.

Кстати, вышеупомянутый запрос Виктора эту блокировку, разумеется, тоже покажет:
Код: sql
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
postgres=# WITH RECURSIVE l AS (
postgres(#   SELECT pid, locktype, mode, granted,
postgres(#  ROW(locktype,database,relation,page,tuple,virtualxid,transactionid,classid,objid,objsubid) obj
postgres(#   FROM pg_locks
postgres(# ), pairs AS (
postgres(#   SELECT w.pid waiter, l.pid locker, l.obj, l.mode
postgres(#   FROM l w
postgres(#   JOIN l ON l.obj IS NOT DISTINCT FROM w.obj AND l.locktype=w.locktype AND NOT l.pid=w.pid AND l.granted
postgres(#   WHERE NOT w.granted
postgres(# ), tree AS (
postgres(#   SELECT l.locker pid, l.locker root, NULL::record obj, NULL AS mode, 0 lvl, locker::text path, array_agg(l.locker) OVER () all_pids
postgres(#   FROM ( SELECT DISTINCT locker FROM pairs l WHERE NOT EXISTS (SELECT 1 FROM pairs WHERE waiter=l.locker) ) l
postgres(#   UNION ALL
postgres(#   SELECT w.waiter pid, tree.root, w.obj, w.mode, tree.lvl+1, tree.path||'.'||w.waiter, all_pids || array_agg(w.waiter) OVER ()
postgres(#   FROM tree JOIN pairs w ON tree.pid=w.locker AND NOT w.waiter = ANY ( all_pids )
postgres(# )
postgres-# SELECT (clock_timestamp() - a.xact_start)::interval(3) AS ts_age,
postgres-#        replace(a.state, 'idle in transaction', 'idletx') state,
postgres-#        (clock_timestamp() - state_change)::interval(3) AS change_age,
postgres-#        a.datname,tree.pid,a.usename,a.client_addr,lvl,
postgres-#        (SELECT count(*) FROM tree p WHERE p.path ~ ('^'||tree.path) AND NOT p.path=tree.path) blocked,
postgres-#        repeat(' .', lvl)||' '||left(regexp_replace(query, '\s+', ' ', 'g'),100) query
postgres-# FROM tree
postgres-# JOIN pg_stat_activity a USING (pid)
postgres-# ORDER BY path;
    ts_age    | state  |  change_age  | datname  | pid  | usename  | client_addr | lvl | blocked |                    query                     
--------------+--------+--------------+----------+------+----------+-------------+-----+---------+----------------------------------------------
 00:03:49.046 | idletx | 00:03:45.447 | postgres | 4185 | postgres |             |   0 |       1 |  select * from t;
 00:03:18.285 | active | 00:03:18.285 | postgres | 6794 | postgres |             |   1 |       0 |  . create index CONCURRENTLY t_idx on t(id);
(2 rows)


Пример с конфликтом на hot standby делать лениво.
...
Рейтинг: 0 / 0
Форумы / PostgreSQL [игнор отключен] [закрыт для гостей] / ExclusiveLock - норма? / 11 сообщений из 11, страница 1 из 1
Целевая тема:
Создать новую тему:
Автор:
Найденые пользователи ...
Разблокировать пользователей ...
Читали форум (0):
Пользователи онлайн (0):
x
x
Закрыть


Просмотр
0 / 0
Close
Debug Console [Select Text]