From cdaf9bbb5f1f734884e0204a4c9e3944431b6d81 Mon Sep 17 00:00:00 2001 From: Joel Jacobson Date: Wed, 8 Oct 2025 09:30:54 +0200 Subject: [PATCH 1/2] Improve LISTEN/NOTIFY test coverage This adds isolation tests to cover previously untested code paths: * Check simple NOTIFY reparenting when parent has no action * Check LISTEN reparenting in subtransaction * Check LISTEN merge path when both outer and inner transactions have actions * Check LISTEN abort path (ROLLBACK TO SAVEPOINT discards pending actions) * Check notification_match function (triggered by hash table duplicate detection) * Check that notifications sent from a backend that has not done LISTEN are properly delivered to a listener in another backend This also adds a test to prepare for the next patch: * Check ChannelHashAddListener array growth --- src/test/isolation/expected/async-notify.out | 114 ++++++++++++++++++- src/test/isolation/specs/async-notify.spec | 68 +++++++++++ 2 files changed, 181 insertions(+), 1 deletion(-) diff --git a/src/test/isolation/expected/async-notify.out b/src/test/isolation/expected/async-notify.out index 556e1805893..443a6eb669f 100644 --- a/src/test/isolation/expected/async-notify.out +++ b/src/test/isolation/expected/async-notify.out @@ -1,4 +1,4 @@ -Parsed test spec with 3 sessions +Parsed test spec with 7 sessions starting permutation: listenc notify1 notify2 notify3 notifyf step listenc: LISTEN c1; LISTEN c2; @@ -47,6 +47,105 @@ notifier: NOTIFY "c2" with payload "payload" from notifier notifier: NOTIFY "c1" with payload "payloads" from notifier notifier: NOTIFY "c2" with payload "payloads" from notifier +starting permutation: listenc notifys_simple +step listenc: LISTEN c1; LISTEN c2; +step notifys_simple: + BEGIN; + SAVEPOINT s1; + NOTIFY c1, 'simple1'; + NOTIFY c2, 'simple2'; + RELEASE SAVEPOINT s1; + COMMIT; + +notifier: NOTIFY "c1" with payload "simple1" from notifier +notifier: NOTIFY "c2" with payload "simple2" from notifier + +starting permutation: lsbegin lssavepoint lslisten lsrelease lscommit lsnotify +step lsbegin: BEGIN; +step lssavepoint: SAVEPOINT s1; +step lslisten: LISTEN c1; LISTEN c2; +step lsrelease: RELEASE SAVEPOINT s1; +step lscommit: COMMIT; +step lsnotify: NOTIFY c1, 'subxact_test'; +listen_subxact: NOTIFY "c1" with payload "subxact_test" from listen_subxact + +starting permutation: lsbegin lslisten_outer lssavepoint lslisten lsrelease lscommit lsnotify +step lsbegin: BEGIN; +step lslisten_outer: LISTEN c3; +step lssavepoint: SAVEPOINT s1; +step lslisten: LISTEN c1; LISTEN c2; +step lsrelease: RELEASE SAVEPOINT s1; +step lscommit: COMMIT; +step lsnotify: NOTIFY c1, 'subxact_test'; +listen_subxact: NOTIFY "c1" with payload "subxact_test" from listen_subxact + +starting permutation: lsbegin lssavepoint lslisten lsrollback lscommit lsnotify_check +step lsbegin: BEGIN; +step lssavepoint: SAVEPOINT s1; +step lslisten: LISTEN c1; LISTEN c2; +step lsrollback: ROLLBACK TO SAVEPOINT s1; +step lscommit: COMMIT; +step lsnotify_check: NOTIFY c1, 'should_not_receive'; + +starting permutation: listenc notify_many_with_dup +step listenc: LISTEN c1; LISTEN c2; +step notify_many_with_dup: + BEGIN; + SELECT pg_notify('c1', 'msg' || s::text) FROM generate_series(1, 17) s; + SELECT pg_notify('c1', 'msg1'); + COMMIT; + +pg_notify +--------- + + + + + + + + + + + + + + + + + +(17 rows) + +pg_notify +--------- + +(1 row) + +notifier: NOTIFY "c1" with payload "msg1" from notifier +notifier: NOTIFY "c1" with payload "msg2" from notifier +notifier: NOTIFY "c1" with payload "msg3" from notifier +notifier: NOTIFY "c1" with payload "msg4" from notifier +notifier: NOTIFY "c1" with payload "msg5" from notifier +notifier: NOTIFY "c1" with payload "msg6" from notifier +notifier: NOTIFY "c1" with payload "msg7" from notifier +notifier: NOTIFY "c1" with payload "msg8" from notifier +notifier: NOTIFY "c1" with payload "msg9" from notifier +notifier: NOTIFY "c1" with payload "msg10" from notifier +notifier: NOTIFY "c1" with payload "msg11" from notifier +notifier: NOTIFY "c1" with payload "msg12" from notifier +notifier: NOTIFY "c1" with payload "msg13" from notifier +notifier: NOTIFY "c1" with payload "msg14" from notifier +notifier: NOTIFY "c1" with payload "msg15" from notifier +notifier: NOTIFY "c1" with payload "msg16" from notifier +notifier: NOTIFY "c1" with payload "msg17" from notifier + +starting permutation: listenc llisten l2listen l3listen lslisten +step listenc: LISTEN c1; LISTEN c2; +step llisten: LISTEN c1; LISTEN c2; +step l2listen: LISTEN c1; +step l3listen: LISTEN c1; +step lslisten: LISTEN c1; LISTEN c2; + starting permutation: llisten notify1 notify2 notify3 notifyf lcheck step llisten: LISTEN c1; LISTEN c2; step notify1: NOTIFY c1; @@ -95,6 +194,8 @@ listener: NOTIFY "c2" with payload "" from notifier starting permutation: l2listen l2begin notify1 lbegins llisten lcommit l2commit l2stop step l2listen: LISTEN c1; +listener2: NOTIFY "c1" with payload "" from notifier +listener2: NOTIFY "c1" with payload "" from notifier step l2begin: BEGIN; step notify1: NOTIFY c1; step lbegins: BEGIN ISOLATION LEVEL SERIALIZABLE; @@ -104,6 +205,17 @@ step l2commit: COMMIT; listener2: NOTIFY "c1" with payload "" from notifier step l2stop: UNLISTEN *; +starting permutation: lch_listen nch_notify lch_check +step lch_listen: LISTEN ch; +step nch_notify: NOTIFY ch, 'aa'; +step lch_check: SELECT 1 AS x; +x +- +1 +(1 row) + +listener_ch: NOTIFY "ch" with payload "aa" from notifier_ch + starting permutation: llisten lbegin usage bignotify usage step llisten: LISTEN c1; LISTEN c2; step lbegin: BEGIN; diff --git a/src/test/isolation/specs/async-notify.spec b/src/test/isolation/specs/async-notify.spec index 0b8cfd91083..0a01e777b98 100644 --- a/src/test/isolation/specs/async-notify.spec +++ b/src/test/isolation/specs/async-notify.spec @@ -31,6 +31,20 @@ step notifys1 { ROLLBACK TO SAVEPOINT s2; COMMIT; } +step notifys_simple { + BEGIN; + SAVEPOINT s1; + NOTIFY c1, 'simple1'; + NOTIFY c2, 'simple2'; + RELEASE SAVEPOINT s1; + COMMIT; +} +step notify_many_with_dup { + BEGIN; + SELECT pg_notify('c1', 'msg' || s::text) FROM generate_series(1, 17) s; + SELECT pg_notify('c1', 'msg1'); + COMMIT; +} step usage { SELECT pg_notification_queue_usage() > 0 AS nonzero; } step bignotify { SELECT count(pg_notify('c1', s::text)) FROM generate_series(1, 1000) s; } teardown { UNLISTEN *; } @@ -53,6 +67,38 @@ step l2begin { BEGIN; } step l2commit { COMMIT; } step l2stop { UNLISTEN *; } +# Third listener session for testing array growth. + +session listener3 +step l3listen { LISTEN c1; } +teardown { UNLISTEN *; } + +# Listener session for cross-session notification test with channel 'ch'. + +session listener_ch +step lch_listen { LISTEN ch; } +step lch_check { SELECT 1 AS x; } +teardown { UNLISTEN *; } + +# Notifier session for cross-session notification test with channel 'ch'. + +session notifier_ch +step nch_notify { NOTIFY ch, 'aa'; } + +# Session for testing LISTEN in subtransaction with separate steps. + +session listen_subxact +step lsbegin { BEGIN; } +step lslisten_outer { LISTEN c3; } +step lssavepoint { SAVEPOINT s1; } +step lslisten { LISTEN c1; LISTEN c2; } +step lsrelease { RELEASE SAVEPOINT s1; } +step lsrollback { ROLLBACK TO SAVEPOINT s1; } +step lscommit { COMMIT; } +step lsnotify { NOTIFY c1, 'subxact_test'; } +step lsnotify_check { NOTIFY c1, 'should_not_receive'; } +teardown { UNLISTEN *; } + # Trivial cases. permutation listenc notify1 notify2 notify3 notifyf @@ -60,6 +106,24 @@ permutation listenc notify1 notify2 notify3 notifyf # Check simple and less-simple deduplication. permutation listenc notifyd1 notifyd2 notifys1 +# Check simple NOTIFY reparenting when parent has no action. +permutation listenc notifys_simple + +# Check LISTEN reparenting in subtransaction. +permutation lsbegin lssavepoint lslisten lsrelease lscommit lsnotify + +# Check LISTEN merge path when both outer and inner transactions have actions. +permutation lsbegin lslisten_outer lssavepoint lslisten lsrelease lscommit lsnotify + +# Check LISTEN abort path (ROLLBACK TO SAVEPOINT discards pending actions). +permutation lsbegin lssavepoint lslisten lsrollback lscommit lsnotify_check + +# Check notification_match function (triggered by hash table duplicate detection). +permutation listenc notify_many_with_dup + +# Check ChannelHashAddListener array growth. +permutation listenc llisten l2listen l3listen lslisten + # Cross-backend notification delivery. We use a "select 1" to force the # listener session to check for notifies. In principle we could just wait # for delivery, but that would require extra support in isolationtester @@ -73,6 +137,10 @@ permutation listenc llisten notify1 notify2 notify3 notifyf lcheck # and notify queue is not empty permutation l2listen l2begin notify1 lbegins llisten lcommit l2commit l2stop +# Check that notifications sent from a backend that has not done LISTEN +# are properly delivered to a listener in another backend. +permutation lch_listen nch_notify lch_check + # Verify that pg_notification_queue_usage correctly reports a non-zero result, # after submitting notifications while another connection is listening for # those notifications and waiting inside an active transaction. We have to -- 2.50.1