понять как такое может быть
Есть дедлок, 2+ транзакции внутри себя работают с одной таблицей в которую инсертят записи, из которой селектят записи, и иногда делают select for update, но судя по коду и ошибке это не этот случай тк for update делается только после инсертов. И ловится дедлок.
Ошибка выглядит так:
2023-08-16 14:22:04.366 GMT [196] ERROR: deadlock detected
2023-08-16 14:22:04.366 GMT [196] DETAIL: Process 196 waits for ShareLock on transaction 2382; blocked by process 199.
Process 199 waits for ShareLock on transaction 2383; blocked by process 196.
Process 196: INSERT INTO "ResourceOccupationEntity" AS t ("poolId","resourceId","statusJson") VALUES ($1, $2, $3) ON CONFLICT DO NOTHING
Process 199: INSERT INTO "ResourceOccupationEntity" AS t ("poolId","resourceId","statusJson") VALUES ($1, $2, $3) ON CONFLICT DO NOTHING
в доке написано что ShareLock берется только во время "CREATE INDEX (without CONCURRENTLY)."
Но это 99.99% не так, тк код который делает инсерт происходит точно после того как отработал код который накатывает схему, в которой может быть какой-то индекс.
Далее могу предположить что "ShareLock" из лога соответствует "Row-Level Lock - FOR SHARE" (хотя ни в доке ни в книжке это не описано). Также смотрю что в книге, в разделе о дедлоках описано что при апдейте выводится также в логи название "ShareLock", и вызвано это блокировкой строки, которая апдейтится. По доке блокировка на строчку которую берет UPDATE это как раз "FOR SHARE". Но самое интересно что такая блокировка не берется при инсерте.
По доке при инсерте берется только табличный "ROW EXCLUSIVE (RowExclusiveLock)" который также берется при UPDATE, но он не конфликтует сам с собой.
В итоге по доке нет ни 1го кейса когда мои запросы (и соответствующие их блокировки) бы конфликтовали, но тем не менее есть дедлок.
Кривая дока? Баг в постгресе?
Помогите пожалуйста 🙂
> в доке написано И правильно написано (если не считать того, что некоторые расширения могут его использовать, ну и в LOCK можно задать что угодно), насколько я помню. > Но это 99.99% не так, Так что наоборот. ;) > код который делает инсерт происходит точно после того как отработал код который накатывает схему, в которой может быть какой-то индекс. И что из того, что он происходит после? Важно только то, в той же транзакции или нет. > хотя ни в доке ни в книжке это не описано Потому что это неправда. ;) Ну и остальное — Ваши фантазии, извините (насколько я пока вижу).
точно не в тойже транзакции. это прям разные стадии работы приложения с ваших слов, если дока верная, то я баг постгреса словил
про фантазии ничего не понял. я привел результаты своих наблюдений в доке, в книжке и в логах.
я правильно понял что вы утверждаете что SharedLock в логах может быть ТОЛЬКО при взятии SHARE (ShareLock), который по доке "Acquired by CREATE INDEX (without CONCURRENTLY)." + можно самому или в экстеншенах? но это же не правда, в книге приводится что такое же название выводится логах при update
А это воспроизводится (особенно хорошо, если в тестовом окружении)? Если да — log_statement = all и всё выяснится. > то я баг постгреса словил Я не верю, что PostgreSQL с чего-то ставит ShareLock там, где он совсем не нужен. > что конкретно вы оспариваете - не понятно Ваши фантазии по поводу того, что ShareLock — это "на самом деле" Row-Level Lock - FOR SHARE и так далее.
окей, почему тогда в книге ShareLock при update ?
Это ShareLock на соседскую транзакцию. В надежде что когда она закончится удастся продолжить свою
Нет, я утверждаю только то, что ShareLock <> какому-либо row lock, и всё. > в книге приводится что такое же название выводится логах при update Правильно приводится — Вы внимательно смотрите в документации, в каком разделе это написано. > окей, почему тогда в книге ShareLock при update ? Разве это ShareLock таблицы?
как это понимать? в разделе блокировок строк приводится что происходит блокирование строк и в логах ShareLock но вы утверждаете "ShareLock <> какому-либо row lock, и всё." при этом как я понимаю из вопрос "Разве это ShareLock таблицы?" то это и не табличный лок. можете объяснить?
> приводится что происходит блокирование строк Строк, а не таблиц. > и в логах ShareLock ShareLock чего? Вот цитата из Вашего лога: ShareLock on transaction 2382 Какое там третье слово? ;) Ладно, кроме шуток: > то это и не табличный лок. Вот именно. Таким образом отражается ожидание транзакциями друг друга... и, кстати, в документации я этого тоже сходу не вижу (хотя это должно быть в разделе https://www.postgresql.org/docs/current/mvcc.html , казалось бы) — написали бы Вы bug report / documentation comment, что ли...
У вас классический deadlock: Session 1: create table t(x integer primary key); begin; insert into t values (1) on conflict do nothing; Session2: begin; insert into t values (2) on conflict do nothing; insert into t values (1) on conflict do nothing; Session1: insert into t values (2) on conflict do nothing;
Или не классический — мы транзакций целиком не видели (но скорее всего да, так и есть). ;)
да, только в приложении это "невозможно" идет create table всех, синхронно только после этого приложение начинает принимать запросы приходит 2 запроса в которых в транзакции пачка инсертов. и вот как они между собой конфликтуют, пока не пойму. ну либо не инсерты конфликтуют... но почему-то именно на этих стейтментах детектится дедлок
Ну так вон же пример того, как именно это происходит. Опять-таки, Вам бы выяснить, что происходит в этих транзакциях, от начала и до deadlock.
А вот и ShareLock в книге
Книга — это хорошо... только вот получается так, что [все] мы об этом откуда-то знаем, а вот документация PostgreSQL — нет. ;)
А я вчера жаловался на документацию.
Если у Вас есть силы и желание её улучшать — надо жаловаться не только тут, но и в -docs (авось, подействует). ;)
create table тут не причём - он до старта транзакции.
да, я понял, спасибо
Обсуждают сегодня