mirror of https://github.com/postgres/postgres
The isolation tests for INSERT ON CONFLICT behavior during CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY (added bypull/266/headbc32a12e0d,2bc7e886fc, and90eae926ab) were disabled in77038d6d0bdue to persistent CI flakiness, after several attempts at stabilization. This commit removes them and introduces a TAP test in test_misc module (010_index_concurrently_upsert.pl) that covers the same scenarios. This new test should hopefully be more stable while providing assurance that the fixes in all those commits (plus81f72115cf) continue to work. Author: Mihail Nikalayeu <mihailnikalayeu@gmail.com> Reported-by: Andres Freund <andres@anarazel.de> Reviewed-by: Álvaro Herrera <alvherre@kurilemu.de> Discussion: https://postgr.es/m/ccssrhafzbp3a3beju3ptyc56a7gbfimj4vwkbokoldofckrc7@bso37rxskjtf Discussion: https://postgr.es/m/CANtu0ogv+6wqRzPK241jik4U95s1pW3MCZ3rX5ZqbFdUysz7Qw@mail.gmail.com Discussion: https://postgr.es/m/202512112014.icpomgc37zx4@alvherre.pgsql
parent
a516b3f00d
commit
e1c971945d
@ -1,123 +0,0 @@ |
||||
Parsed test spec with 5 sessions |
||||
|
||||
starting permutation: s1_attach_invalidate_catalog_snapshot s4_wakeup_s1_setup s3_start_create_index s1_start_upsert s4_wakeup_define_index_before_set_valid s2_start_upsert s5_wakeup_s1_from_invalidate_catalog_snapshot s4_wakeup_s2 s4_wakeup_s1 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_attach_invalidate_catalog_snapshot: |
||||
SELECT injection_points_attach('invalidate-catalog-snapshot-end', 'wait'); |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s1_setup: |
||||
SELECT CASE WHEN |
||||
(SELECT pid FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' AND |
||||
wait_event = 'invalidate-catalog-snapshot-end') IS NOT NULL |
||||
THEN injection_points_wakeup('invalidate-catalog-snapshot-end') |
||||
END; |
||||
|
||||
case |
||||
---- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_create_index: |
||||
CREATE UNIQUE INDEX CONCURRENTLY tbl_pkey_special_duplicate ON test.tbl(abs(i)) WHERE i < 10000; |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES(13,now()) ON CONFLICT (abs(i)) WHERE i < 100 DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_define_index_before_set_valid: |
||||
SELECT injection_points_detach('define-index-before-set-valid'); |
||||
SELECT injection_points_wakeup('define-index-before-set-valid'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES(13,now()) ON CONFLICT (abs(i)) WHERE i < 100 DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s5_wakeup_s1_from_invalidate_catalog_snapshot: |
||||
DO $$ |
||||
DECLARE |
||||
v_waiting_pid INTEGER; |
||||
BEGIN |
||||
LOOP |
||||
SELECT pid INTO v_waiting_pid |
||||
FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' |
||||
AND wait_event = 'invalidate-catalog-snapshot-end' |
||||
LIMIT 1; |
||||
EXIT WHEN v_waiting_pid IS NOT NULL; |
||||
PERFORM pg_sleep(100); |
||||
END LOOP; |
||||
END |
||||
$$; |
||||
|
||||
SELECT injection_points_detach('invalidate-catalog-snapshot-end'); |
||||
SELECT injection_points_wakeup('invalidate-catalog-snapshot-end'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_create_index: <... completed> |
||||
@ -1,124 +0,0 @@ |
||||
Parsed test spec with 5 sessions |
||||
|
||||
starting permutation: s1_attach_invalidate_catalog_snapshot s4_wakeup_s1_setup s3_start_create_index s1_start_upsert s4_wakeup_define_index_before_set_valid s2_start_upsert s5_wakeup_s1_from_invalidate_catalog_snapshot s4_wakeup_s2 s4_wakeup_s1 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_attach_invalidate_catalog_snapshot: |
||||
SELECT injection_points_attach('invalidate-catalog-snapshot-end', 'wait'); |
||||
<waiting ...> |
||||
step s4_wakeup_s1_setup: |
||||
SELECT CASE WHEN |
||||
(SELECT pid FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' AND |
||||
wait_event = 'invalidate-catalog-snapshot-end') IS NOT NULL |
||||
THEN injection_points_wakeup('invalidate-catalog-snapshot-end') |
||||
END; |
||||
|
||||
case |
||||
---- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_attach_invalidate_catalog_snapshot: <... completed> |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_create_index: |
||||
CREATE UNIQUE INDEX CONCURRENTLY tbl_pkey_special_duplicate ON test.tbl(abs(i)) WHERE i < 10000; |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES(13,now()) ON CONFLICT (abs(i)) WHERE i < 100 DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_define_index_before_set_valid: |
||||
SELECT injection_points_detach('define-index-before-set-valid'); |
||||
SELECT injection_points_wakeup('define-index-before-set-valid'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES(13,now()) ON CONFLICT (abs(i)) WHERE i < 100 DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s5_wakeup_s1_from_invalidate_catalog_snapshot: |
||||
DO $$ |
||||
DECLARE |
||||
v_waiting_pid INTEGER; |
||||
BEGIN |
||||
LOOP |
||||
SELECT pid INTO v_waiting_pid |
||||
FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' |
||||
AND wait_event = 'invalidate-catalog-snapshot-end' |
||||
LIMIT 1; |
||||
EXIT WHEN v_waiting_pid IS NOT NULL; |
||||
PERFORM pg_sleep(100); |
||||
END LOOP; |
||||
END |
||||
$$; |
||||
|
||||
SELECT injection_points_detach('invalidate-catalog-snapshot-end'); |
||||
SELECT injection_points_wakeup('invalidate-catalog-snapshot-end'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_create_index: <... completed> |
||||
@ -1,123 +0,0 @@ |
||||
Parsed test spec with 5 sessions |
||||
|
||||
starting permutation: s1_attach_invalidate_catalog_snapshot s4_wakeup_s1_setup s3_start_create_index s1_start_upsert s4_wakeup_define_index_before_set_valid s2_start_upsert s5_wakeup_s1_from_invalidate_catalog_snapshot s4_wakeup_s2 s4_wakeup_s1 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_attach_invalidate_catalog_snapshot: |
||||
SELECT injection_points_attach('invalidate-catalog-snapshot-end', 'wait'); |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s1_setup: |
||||
SELECT CASE WHEN |
||||
(SELECT pid FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' AND |
||||
wait_event = 'invalidate-catalog-snapshot-end') IS NOT NULL |
||||
THEN injection_points_wakeup('invalidate-catalog-snapshot-end') |
||||
END; |
||||
|
||||
case |
||||
---- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_create_index: |
||||
CREATE UNIQUE INDEX CONCURRENTLY tbl_pkey_duplicate ON test.tbl(i); |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_define_index_before_set_valid: |
||||
SELECT injection_points_detach('define-index-before-set-valid'); |
||||
SELECT injection_points_wakeup('define-index-before-set-valid'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s5_wakeup_s1_from_invalidate_catalog_snapshot: |
||||
DO $$ |
||||
DECLARE |
||||
v_waiting_pid INTEGER; |
||||
BEGIN |
||||
LOOP |
||||
SELECT pid INTO v_waiting_pid |
||||
FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' |
||||
AND wait_event = 'invalidate-catalog-snapshot-end' |
||||
LIMIT 1; |
||||
EXIT WHEN v_waiting_pid IS NOT NULL; |
||||
PERFORM pg_sleep(100); |
||||
END LOOP; |
||||
END |
||||
$$; |
||||
|
||||
SELECT injection_points_detach('invalidate-catalog-snapshot-end'); |
||||
SELECT injection_points_wakeup('invalidate-catalog-snapshot-end'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_create_index: <... completed> |
||||
@ -1,124 +0,0 @@ |
||||
Parsed test spec with 5 sessions |
||||
|
||||
starting permutation: s1_attach_invalidate_catalog_snapshot s4_wakeup_s1_setup s3_start_create_index s1_start_upsert s4_wakeup_define_index_before_set_valid s2_start_upsert s5_wakeup_s1_from_invalidate_catalog_snapshot s4_wakeup_s2 s4_wakeup_s1 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_attach_invalidate_catalog_snapshot: |
||||
SELECT injection_points_attach('invalidate-catalog-snapshot-end', 'wait'); |
||||
<waiting ...> |
||||
step s4_wakeup_s1_setup: |
||||
SELECT CASE WHEN |
||||
(SELECT pid FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' AND |
||||
wait_event = 'invalidate-catalog-snapshot-end') IS NOT NULL |
||||
THEN injection_points_wakeup('invalidate-catalog-snapshot-end') |
||||
END; |
||||
|
||||
case |
||||
---- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_attach_invalidate_catalog_snapshot: <... completed> |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_create_index: |
||||
CREATE UNIQUE INDEX CONCURRENTLY tbl_pkey_duplicate ON test.tbl(i); |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_define_index_before_set_valid: |
||||
SELECT injection_points_detach('define-index-before-set-valid'); |
||||
SELECT injection_points_wakeup('define-index-before-set-valid'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s5_wakeup_s1_from_invalidate_catalog_snapshot: |
||||
DO $$ |
||||
DECLARE |
||||
v_waiting_pid INTEGER; |
||||
BEGIN |
||||
LOOP |
||||
SELECT pid INTO v_waiting_pid |
||||
FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' |
||||
AND wait_event = 'invalidate-catalog-snapshot-end' |
||||
LIMIT 1; |
||||
EXIT WHEN v_waiting_pid IS NOT NULL; |
||||
PERFORM pg_sleep(100); |
||||
END LOOP; |
||||
END |
||||
$$; |
||||
|
||||
SELECT injection_points_detach('invalidate-catalog-snapshot-end'); |
||||
SELECT injection_points_wakeup('invalidate-catalog-snapshot-end'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_create_index: <... completed> |
||||
@ -1,238 +0,0 @@ |
||||
Parsed test spec with 4 sessions |
||||
|
||||
starting permutation: s3_setup_wait_before_set_dead s3_start_reindex s1_start_upsert s4_wakeup_to_set_dead s2_start_upsert s4_wakeup_s1 s4_wakeup_s2 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_set_local |
||||
-------------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_setup_wait_before_set_dead: |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_reindex: |
||||
REINDEX INDEX CONCURRENTLY test.tbl_pkey; |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT ON CONSTRAINT tbl_pkey DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_to_set_dead: |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-set-dead'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT ON CONSTRAINT tbl_pkey DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_reindex: <... completed> |
||||
|
||||
starting permutation: s3_setup_wait_before_swap s3_start_reindex s1_start_upsert s4_wakeup_to_swap s2_start_upsert s4_wakeup_s2 s4_wakeup_s1 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_set_local |
||||
-------------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_setup_wait_before_swap: |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-swap', 'wait'); |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_reindex: |
||||
REINDEX INDEX CONCURRENTLY test.tbl_pkey; |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT ON CONSTRAINT tbl_pkey DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_to_swap: |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-swap'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-swap'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT ON CONSTRAINT tbl_pkey DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_reindex: <... completed> |
||||
|
||||
starting permutation: s3_setup_wait_before_set_dead s3_start_reindex s1_start_upsert s2_start_upsert s4_wakeup_s1 s4_wakeup_to_set_dead s4_wakeup_s2 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_set_local |
||||
-------------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_setup_wait_before_set_dead: |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_reindex: |
||||
REINDEX INDEX CONCURRENTLY test.tbl_pkey; |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT ON CONSTRAINT tbl_pkey DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT ON CONSTRAINT tbl_pkey DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s4_wakeup_to_set_dead: |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-set-dead'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_reindex: <... completed> |
||||
@ -1,238 +0,0 @@ |
||||
Parsed test spec with 4 sessions |
||||
|
||||
starting permutation: s3_setup_wait_before_set_dead s3_start_reindex s1_start_upsert s4_wakeup_to_set_dead s2_start_upsert s4_wakeup_s1 s4_wakeup_s2 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_set_local |
||||
-------------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_setup_wait_before_set_dead: |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_reindex: |
||||
REINDEX INDEX CONCURRENTLY test.tbl_partition_pkey; |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_to_set_dead: |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-set-dead'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_reindex: <... completed> |
||||
|
||||
starting permutation: s3_setup_wait_before_swap s3_start_reindex s1_start_upsert s4_wakeup_to_swap s2_start_upsert s4_wakeup_s2 s4_wakeup_s1 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_set_local |
||||
-------------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_setup_wait_before_swap: |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-swap', 'wait'); |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_reindex: |
||||
REINDEX INDEX CONCURRENTLY test.tbl_partition_pkey; |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_to_swap: |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-swap'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-swap'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_reindex: <... completed> |
||||
|
||||
starting permutation: s3_setup_wait_before_set_dead s3_start_reindex s1_start_upsert s2_start_upsert s4_wakeup_s1 s4_wakeup_to_set_dead s4_wakeup_s2 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_set_local |
||||
-------------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_setup_wait_before_set_dead: |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_reindex: |
||||
REINDEX INDEX CONCURRENTLY test.tbl_partition_pkey; |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s4_wakeup_to_set_dead: |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-set-dead'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_reindex: <... completed> |
||||
@ -1,238 +0,0 @@ |
||||
Parsed test spec with 4 sessions |
||||
|
||||
starting permutation: s3_setup_wait_before_set_dead s3_start_reindex s1_start_upsert s4_wakeup_to_set_dead s2_start_upsert s4_wakeup_s1 s4_wakeup_s2 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_set_local |
||||
-------------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_setup_wait_before_set_dead: |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_reindex: |
||||
REINDEX INDEX CONCURRENTLY test.tbl_pkey; |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_to_set_dead: |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-set-dead'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_reindex: <... completed> |
||||
|
||||
starting permutation: s3_setup_wait_before_swap s3_start_reindex s1_start_upsert s4_wakeup_to_swap s2_start_upsert s4_wakeup_s2 s4_wakeup_s1 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_set_local |
||||
-------------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_setup_wait_before_swap: |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-swap', 'wait'); |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_reindex: |
||||
REINDEX INDEX CONCURRENTLY test.tbl_pkey; |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_to_swap: |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-swap'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-swap'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_reindex: <... completed> |
||||
|
||||
starting permutation: s3_setup_wait_before_set_dead s3_start_reindex s1_start_upsert s2_start_upsert s4_wakeup_s1 s4_wakeup_to_set_dead s4_wakeup_s2 |
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_set_local |
||||
-------------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_setup_wait_before_set_dead: |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
|
||||
injection_points_attach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s3_start_reindex: |
||||
REINDEX INDEX CONCURRENTLY test.tbl_pkey; |
||||
<waiting ...> |
||||
step s1_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s2_start_upsert: |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
<waiting ...> |
||||
step s4_wakeup_s1: |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s1_start_upsert: <... completed> |
||||
step s4_wakeup_to_set_dead: |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-set-dead'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s4_wakeup_s2: |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
|
||||
injection_points_detach |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
injection_points_wakeup |
||||
----------------------- |
||||
|
||||
(1 row) |
||||
|
||||
step s2_start_upsert: <... completed> |
||||
step s3_start_reindex: <... completed> |
||||
@ -1,124 +0,0 @@ |
||||
# This test verifies INSERT ON CONFLICT DO UPDATE behavior concurrent with |
||||
# CREATE INDEX CONCURRENTLY a partial index. |
||||
# |
||||
# - s1: UPSERT a tuple |
||||
# - s2: UPSERT the same tuple |
||||
# - s3: CREATE UNIQUE INDEX CONCURRENTLY (with a predicate) |
||||
# |
||||
# - s4 and s5: control concurrency via injection points |
||||
|
||||
setup |
||||
{ |
||||
CREATE EXTENSION injection_points; |
||||
CREATE SCHEMA test; |
||||
CREATE UNLOGGED TABLE test.tbl(i int, updated_at timestamp); |
||||
CREATE UNIQUE INDEX tbl_pkey_special ON test.tbl(abs(i)) WHERE i < 1000; |
||||
ALTER TABLE test.tbl SET (parallel_workers=0); |
||||
} |
||||
|
||||
teardown |
||||
{ |
||||
DROP SCHEMA test CASCADE; |
||||
DROP EXTENSION injection_points; |
||||
} |
||||
|
||||
session s1 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
} |
||||
step s1_attach_invalidate_catalog_snapshot |
||||
{ |
||||
SELECT injection_points_attach('invalidate-catalog-snapshot-end', 'wait'); |
||||
} |
||||
step s1_start_upsert |
||||
{ |
||||
INSERT INTO test.tbl VALUES(13,now()) ON CONFLICT (abs(i)) WHERE i < 100 DO UPDATE SET updated_at = now(); |
||||
} |
||||
|
||||
session s2 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
} |
||||
step s2_start_upsert |
||||
{ |
||||
INSERT INTO test.tbl VALUES(13,now()) ON CONFLICT (abs(i)) WHERE i < 100 DO UPDATE SET updated_at = now(); |
||||
} |
||||
|
||||
session s3 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('define-index-before-set-valid', 'wait'); |
||||
} |
||||
step s3_start_create_index |
||||
{ |
||||
CREATE UNIQUE INDEX CONCURRENTLY tbl_pkey_special_duplicate ON test.tbl(abs(i)) WHERE i < 10000; |
||||
} |
||||
|
||||
session s4 |
||||
# Step s1_attach_invalidate_catalog_snapshot sleeps or not depending on |
||||
# build conditions (CATCACHE_FORCE_RELEASE). Here we send a wakeup signal if |
||||
# it's sleeping or do nothing otherwise, and print a null value in either |
||||
# case. |
||||
step s4_wakeup_s1_setup |
||||
{ |
||||
SELECT CASE WHEN |
||||
(SELECT pid FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' AND |
||||
wait_event = 'invalidate-catalog-snapshot-end') IS NOT NULL |
||||
THEN injection_points_wakeup('invalidate-catalog-snapshot-end') |
||||
END; |
||||
} |
||||
step s4_wakeup_s1 |
||||
{ |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
} |
||||
step s4_wakeup_s2 |
||||
{ |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
} |
||||
step s4_wakeup_define_index_before_set_valid |
||||
{ |
||||
SELECT injection_points_detach('define-index-before-set-valid'); |
||||
SELECT injection_points_wakeup('define-index-before-set-valid'); |
||||
} |
||||
|
||||
session s5 |
||||
step s5_wakeup_s1_from_invalidate_catalog_snapshot |
||||
{ |
||||
DO $$ |
||||
DECLARE |
||||
v_waiting_pid INTEGER; |
||||
BEGIN |
||||
LOOP |
||||
SELECT pid INTO v_waiting_pid |
||||
FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' |
||||
AND wait_event = 'invalidate-catalog-snapshot-end' |
||||
LIMIT 1; |
||||
EXIT WHEN v_waiting_pid IS NOT NULL; |
||||
PERFORM pg_sleep(100); |
||||
END LOOP; |
||||
END |
||||
$$; |
||||
|
||||
SELECT injection_points_detach('invalidate-catalog-snapshot-end'); |
||||
SELECT injection_points_wakeup('invalidate-catalog-snapshot-end'); |
||||
} |
||||
|
||||
permutation |
||||
s1_attach_invalidate_catalog_snapshot |
||||
s4_wakeup_s1_setup |
||||
s3_start_create_index(s1_start_upsert, s2_start_upsert) |
||||
s1_start_upsert |
||||
s4_wakeup_define_index_before_set_valid |
||||
s2_start_upsert(s1_start_upsert) |
||||
s5_wakeup_s1_from_invalidate_catalog_snapshot |
||||
s4_wakeup_s2 |
||||
s4_wakeup_s1 |
||||
@ -1,123 +0,0 @@ |
||||
# This test verifies INSERT ON CONFLICT DO UPDATE behavior concurrent with |
||||
# CREATE INDEX CONCURRENTLY. |
||||
# |
||||
# - s1: UPSERT a tuple |
||||
# - s2: UPSERT the same tuple |
||||
# - s3: CREATE UNIQUE INDEX CONCURRENTLY |
||||
# |
||||
# - s4: Control concurrency using injection points |
||||
|
||||
setup |
||||
{ |
||||
CREATE EXTENSION injection_points; |
||||
CREATE SCHEMA test; |
||||
CREATE UNLOGGED TABLE test.tbl(i int primary key, updated_at timestamp); |
||||
ALTER TABLE test.tbl SET (parallel_workers=0); |
||||
} |
||||
|
||||
teardown |
||||
{ |
||||
DROP SCHEMA test CASCADE; |
||||
DROP EXTENSION injection_points; |
||||
} |
||||
|
||||
session s1 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
} |
||||
step s1_attach_invalidate_catalog_snapshot |
||||
{ |
||||
SELECT injection_points_attach('invalidate-catalog-snapshot-end', 'wait'); |
||||
} |
||||
step s1_start_upsert |
||||
{ |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
} |
||||
|
||||
session s2 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
} |
||||
step s2_start_upsert |
||||
{ |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
} |
||||
|
||||
session s3 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('define-index-before-set-valid', 'wait'); |
||||
} |
||||
step s3_start_create_index |
||||
{ |
||||
CREATE UNIQUE INDEX CONCURRENTLY tbl_pkey_duplicate ON test.tbl(i); |
||||
} |
||||
|
||||
session s4 |
||||
# Step s1_attach_invalidate_catalog_snapshot sleeps or not depending on |
||||
# build conditions (CATCACHE_FORCE_RELEASE). Here we send a wakeup signal if |
||||
# it's sleeping or do nothing otherwise, and print a null value in either |
||||
# case. |
||||
step s4_wakeup_s1_setup |
||||
{ |
||||
SELECT CASE WHEN |
||||
(SELECT pid FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' AND |
||||
wait_event = 'invalidate-catalog-snapshot-end') IS NOT NULL |
||||
THEN injection_points_wakeup('invalidate-catalog-snapshot-end') |
||||
END; |
||||
} |
||||
step s4_wakeup_s1 |
||||
{ |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
} |
||||
step s4_wakeup_s2 |
||||
{ |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
} |
||||
step s4_wakeup_define_index_before_set_valid |
||||
{ |
||||
SELECT injection_points_detach('define-index-before-set-valid'); |
||||
SELECT injection_points_wakeup('define-index-before-set-valid'); |
||||
} |
||||
|
||||
session s5 |
||||
step s5_wakeup_s1_from_invalidate_catalog_snapshot |
||||
{ |
||||
DO $$ |
||||
DECLARE |
||||
v_waiting_pid INTEGER; |
||||
BEGIN |
||||
LOOP |
||||
SELECT pid INTO v_waiting_pid |
||||
FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' |
||||
AND wait_event = 'invalidate-catalog-snapshot-end' |
||||
LIMIT 1; |
||||
EXIT WHEN v_waiting_pid IS NOT NULL; |
||||
PERFORM pg_sleep(100); |
||||
END LOOP; |
||||
END |
||||
$$; |
||||
|
||||
SELECT injection_points_detach('invalidate-catalog-snapshot-end'); |
||||
SELECT injection_points_wakeup('invalidate-catalog-snapshot-end'); |
||||
} |
||||
|
||||
permutation |
||||
s1_attach_invalidate_catalog_snapshot |
||||
s4_wakeup_s1_setup |
||||
s3_start_create_index(s1_start_upsert, s2_start_upsert) |
||||
s1_start_upsert |
||||
s4_wakeup_define_index_before_set_valid |
||||
s2_start_upsert(s1_start_upsert) |
||||
s5_wakeup_s1_from_invalidate_catalog_snapshot |
||||
s4_wakeup_s2 |
||||
s4_wakeup_s1 |
||||
@ -1,110 +0,0 @@ |
||||
# Test race conditions involving: |
||||
# |
||||
# - s1: UPSERT a tuple |
||||
# - s2: UPSERT the same tuple |
||||
# - s3: concurrently REINDEX the primary key |
||||
# |
||||
# - s4: operations with injection points |
||||
|
||||
setup |
||||
{ |
||||
CREATE EXTENSION injection_points; |
||||
CREATE SCHEMA test; |
||||
CREATE UNLOGGED TABLE test.tbl(i int primary key, updated_at timestamp); |
||||
ALTER TABLE test.tbl SET (parallel_workers=0); |
||||
} |
||||
|
||||
teardown |
||||
{ |
||||
DROP SCHEMA test CASCADE; |
||||
DROP EXTENSION injection_points; |
||||
} |
||||
|
||||
session s1 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
} |
||||
step s1_start_upsert |
||||
{ |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT ON CONSTRAINT tbl_pkey DO UPDATE SET updated_at = now(); |
||||
} |
||||
|
||||
session s2 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
} |
||||
step s2_start_upsert |
||||
{ |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT ON CONSTRAINT tbl_pkey DO UPDATE SET updated_at = now(); |
||||
} |
||||
|
||||
session s3 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
} |
||||
step s3_setup_wait_before_set_dead |
||||
{ |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
} |
||||
step s3_setup_wait_before_swap |
||||
{ |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-swap', 'wait'); |
||||
} |
||||
step s3_start_reindex |
||||
{ |
||||
REINDEX INDEX CONCURRENTLY test.tbl_pkey; |
||||
} |
||||
|
||||
session s4 |
||||
step s4_wakeup_to_swap |
||||
{ |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-swap'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-swap'); |
||||
} |
||||
step s4_wakeup_s1 |
||||
{ |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
} |
||||
step s4_wakeup_s2 |
||||
{ |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
} |
||||
step s4_wakeup_to_set_dead |
||||
{ |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-set-dead'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-set-dead'); |
||||
} |
||||
|
||||
permutation |
||||
s3_setup_wait_before_set_dead |
||||
s3_start_reindex(s1_start_upsert, s2_start_upsert) |
||||
s1_start_upsert(s4_wakeup_s2) |
||||
s4_wakeup_to_set_dead |
||||
s2_start_upsert(s1_start_upsert) |
||||
s4_wakeup_s1 |
||||
s4_wakeup_s2 |
||||
|
||||
permutation |
||||
s3_setup_wait_before_swap |
||||
s3_start_reindex(s1_start_upsert, s2_start_upsert) |
||||
s1_start_upsert(s4_wakeup_s2) |
||||
s4_wakeup_to_swap |
||||
s2_start_upsert(s1_start_upsert) |
||||
s4_wakeup_s2 |
||||
s4_wakeup_s1 |
||||
|
||||
permutation |
||||
s3_setup_wait_before_set_dead |
||||
s3_start_reindex(s1_start_upsert, s2_start_upsert) |
||||
s1_start_upsert(s4_wakeup_s2) |
||||
s2_start_upsert(s1_start_upsert) |
||||
s4_wakeup_s1 |
||||
s4_wakeup_to_set_dead |
||||
s4_wakeup_s2 |
||||
@ -1,113 +0,0 @@ |
||||
# This test verifies INSERT ON CONFLICT DO UPDATE behavior on partitioned |
||||
# tables concurrent with REINDEX CONCURRENTLY. |
||||
# |
||||
# - s1: UPSERT a tuple |
||||
# - s2: UPSERT the same tuple |
||||
# - s3: concurrently REINDEX the primary key index |
||||
# |
||||
# - s4: controls concurrency via injection points |
||||
|
||||
setup |
||||
{ |
||||
CREATE EXTENSION injection_points; |
||||
CREATE SCHEMA test; |
||||
CREATE TABLE test.tbl(i int primary key, updated_at timestamp) PARTITION BY RANGE (i); |
||||
CREATE TABLE test.tbl_partition PARTITION OF test.tbl |
||||
FOR VALUES FROM (0) TO (10000) |
||||
WITH (parallel_workers = 0); |
||||
} |
||||
|
||||
teardown |
||||
{ |
||||
DROP SCHEMA test CASCADE; |
||||
DROP EXTENSION injection_points; |
||||
} |
||||
|
||||
session s1 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
} |
||||
step s1_start_upsert |
||||
{ |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
} |
||||
|
||||
session s2 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
} |
||||
step s2_start_upsert |
||||
{ |
||||
INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
} |
||||
|
||||
session s3 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
} |
||||
step s3_setup_wait_before_set_dead |
||||
{ |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
} |
||||
step s3_setup_wait_before_swap |
||||
{ |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-swap', 'wait'); |
||||
} |
||||
step s3_start_reindex |
||||
{ |
||||
REINDEX INDEX CONCURRENTLY test.tbl_partition_pkey; |
||||
} |
||||
|
||||
session s4 |
||||
step s4_wakeup_to_swap |
||||
{ |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-swap'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-swap'); |
||||
} |
||||
step s4_wakeup_s1 |
||||
{ |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
} |
||||
step s4_wakeup_s2 |
||||
{ |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
} |
||||
step s4_wakeup_to_set_dead |
||||
{ |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-set-dead'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-set-dead'); |
||||
} |
||||
|
||||
permutation |
||||
s3_setup_wait_before_set_dead |
||||
s3_start_reindex(s1_start_upsert, s2_start_upsert) |
||||
s1_start_upsert(s4_wakeup_s2) |
||||
s4_wakeup_to_set_dead |
||||
s2_start_upsert(s1_start_upsert) |
||||
s4_wakeup_s1 |
||||
s4_wakeup_s2 |
||||
|
||||
permutation |
||||
s3_setup_wait_before_swap |
||||
s3_start_reindex(s1_start_upsert, s2_start_upsert) |
||||
s1_start_upsert(s4_wakeup_s2) |
||||
s4_wakeup_to_swap |
||||
s2_start_upsert(s1_start_upsert) |
||||
s4_wakeup_s2 |
||||
s4_wakeup_s1 |
||||
|
||||
permutation |
||||
s3_setup_wait_before_set_dead |
||||
s3_start_reindex(s1_start_upsert, s2_start_upsert) |
||||
s1_start_upsert(s4_wakeup_s2) |
||||
s2_start_upsert(s1_start_upsert) |
||||
s4_wakeup_s1 |
||||
s4_wakeup_to_set_dead |
||||
s4_wakeup_s2 |
||||
@ -1,111 +0,0 @@ |
||||
# This test verifies INSERT ON CONFLICT DO UPDATE behavior concurrent with |
||||
# REINDEX CONCURRENTLY. |
||||
# |
||||
# - s1: UPSERT a tuple |
||||
# - s2: UPSERT the same tuple |
||||
# - s3: REINDEX concurrent primary key index |
||||
# |
||||
# - s4: controls concurrency via injection points |
||||
|
||||
setup |
||||
{ |
||||
CREATE EXTENSION injection_points; |
||||
CREATE SCHEMA test; |
||||
CREATE UNLOGGED TABLE test.tbl (i int PRIMARY KEY, updated_at timestamp); |
||||
ALTER TABLE test.tbl SET (parallel_workers=0); |
||||
} |
||||
|
||||
teardown |
||||
{ |
||||
DROP SCHEMA test CASCADE; |
||||
DROP EXTENSION injection_points; |
||||
} |
||||
|
||||
session s1 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
} |
||||
step s1_start_upsert |
||||
{ |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
} |
||||
|
||||
session s2 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
} |
||||
step s2_start_upsert |
||||
{ |
||||
INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
} |
||||
|
||||
session s3 |
||||
setup |
||||
{ |
||||
SELECT injection_points_set_local(); |
||||
} |
||||
step s3_setup_wait_before_set_dead |
||||
{ |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
} |
||||
step s3_setup_wait_before_swap |
||||
{ |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-swap', 'wait'); |
||||
} |
||||
step s3_start_reindex |
||||
{ |
||||
REINDEX INDEX CONCURRENTLY test.tbl_pkey; |
||||
} |
||||
|
||||
session s4 |
||||
step s4_wakeup_to_swap |
||||
{ |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-swap'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-swap'); |
||||
} |
||||
step s4_wakeup_s1 |
||||
{ |
||||
SELECT injection_points_detach('check-exclusion-or-unique-constraint-no-conflict'); |
||||
SELECT injection_points_wakeup('check-exclusion-or-unique-constraint-no-conflict'); |
||||
} |
||||
step s4_wakeup_s2 |
||||
{ |
||||
SELECT injection_points_detach('exec-insert-before-insert-speculative'); |
||||
SELECT injection_points_wakeup('exec-insert-before-insert-speculative'); |
||||
} |
||||
step s4_wakeup_to_set_dead |
||||
{ |
||||
SELECT injection_points_detach('reindex-relation-concurrently-before-set-dead'); |
||||
SELECT injection_points_wakeup('reindex-relation-concurrently-before-set-dead'); |
||||
} |
||||
|
||||
permutation |
||||
s3_setup_wait_before_set_dead |
||||
s3_start_reindex(s1_start_upsert, s2_start_upsert) |
||||
s1_start_upsert(s4_wakeup_s2) |
||||
s4_wakeup_to_set_dead |
||||
s2_start_upsert(s1_start_upsert) |
||||
s4_wakeup_s1 |
||||
s4_wakeup_s2 |
||||
|
||||
permutation |
||||
s3_setup_wait_before_swap |
||||
s3_start_reindex(s1_start_upsert, s2_start_upsert) |
||||
s1_start_upsert(s4_wakeup_s2) |
||||
s4_wakeup_to_swap |
||||
s2_start_upsert(s1_start_upsert) |
||||
s4_wakeup_s2 |
||||
s4_wakeup_s1 |
||||
|
||||
permutation |
||||
s3_setup_wait_before_set_dead |
||||
s3_start_reindex(s1_start_upsert, s2_start_upsert) |
||||
s1_start_upsert(s4_wakeup_s2) |
||||
s2_start_upsert(s1_start_upsert) |
||||
s4_wakeup_s1 |
||||
s4_wakeup_to_set_dead |
||||
s4_wakeup_s2 |
||||
@ -0,0 +1,902 @@ |
||||
|
||||
# Copyright (c) 2025, PostgreSQL Global Development Group |
||||
|
||||
# Test INSERT ON CONFLICT DO UPDATE behavior concurrent with |
||||
# CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY. |
||||
# |
||||
# These tests verify the fix for "duplicate key value violates unique |
||||
# constraint" errors that occurred when infer_arbiter_indexes() only considered |
||||
# indisvalid indexes, causing different transactions to use different arbiter |
||||
# indexes. |
||||
|
||||
use strict; |
||||
use warnings FATAL => 'all'; |
||||
|
||||
use PostgreSQL::Test::Cluster; |
||||
use PostgreSQL::Test::Utils; |
||||
use Test::More; |
||||
|
||||
plan skip_all => 'Injection points not supported by this build' |
||||
unless $ENV{enable_injection_points} eq 'yes'; |
||||
|
||||
# Node initialization |
||||
my $node = PostgreSQL::Test::Cluster->new('node'); |
||||
$node->init(); |
||||
$node->start(); |
||||
|
||||
# Check if the extension injection_points is available |
||||
plan skip_all => 'Extension injection_points not installed' |
||||
unless $node->check_extension('injection_points'); |
||||
|
||||
$node->safe_psql('postgres', 'CREATE EXTENSION injection_points;'); |
||||
|
||||
$node->safe_psql( |
||||
'postgres', q[ |
||||
CREATE SCHEMA test; |
||||
CREATE UNLOGGED TABLE test.tblpk (i int PRIMARY KEY, updated_at timestamp); |
||||
ALTER TABLE test.tblpk SET (parallel_workers=0); |
||||
|
||||
CREATE TABLE test.tblparted(i int primary key, updated_at timestamp) PARTITION BY RANGE (i); |
||||
CREATE TABLE test.tbl_partition PARTITION OF test.tblparted |
||||
FOR VALUES FROM (0) TO (10000) |
||||
WITH (parallel_workers = 0); |
||||
|
||||
CREATE UNLOGGED TABLE test.tblexpr(i int, updated_at timestamp); |
||||
CREATE UNIQUE INDEX tbl_pkey_special ON test.tblexpr(abs(i)) WHERE i < 1000; |
||||
ALTER TABLE test.tblexpr SET (parallel_workers=0); |
||||
|
||||
]); |
||||
|
||||
############################################################################ |
||||
note('Test: REINDEX CONCURRENTLY + UPSERT (wakeup at set-dead phase)'); |
||||
|
||||
# Create sessions with on_error_stop => 0 so psql doesn't exit on SQL errors. |
||||
# This allows us to collect stderr and detect errors after the test completes. |
||||
my $s1 = $node->background_psql('postgres', on_error_stop => 0); |
||||
my $s2 = $node->background_psql('postgres', on_error_stop => 0); |
||||
my $s3 = $node->background_psql('postgres', on_error_stop => 0); |
||||
|
||||
# Setup injection points for each session |
||||
$s1->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
]); |
||||
|
||||
$s2->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
]); |
||||
|
||||
# s3 starts REINDEX (will block on reindex-relation-concurrently-before-set-dead) |
||||
$s3->query_until( |
||||
qr/starting_reindex/, q[ |
||||
\echo starting_reindex |
||||
REINDEX INDEX CONCURRENTLY test.tblpk_pkey; |
||||
]); |
||||
|
||||
# Wait for s3 to hit injection point |
||||
ok_injection_point($node, 'reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
# s1 starts UPSERT (will block on check-exclusion-or-unique-constraint-no-conflict) |
||||
$s1->query_until( |
||||
qr/starting_upsert_s1/, q[ |
||||
\echo starting_upsert_s1 |
||||
INSERT INTO test.tblpk VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
# Wait for s1 to hit injection point |
||||
ok_injection_point($node, 'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
# Wakeup s3 to continue (reindex-relation-concurrently-before-set-dead) |
||||
wakeup_injection_point($node, |
||||
'reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
# s2 starts UPSERT (will block on exec-insert-before-insert-speculative) |
||||
$s2->query_until( |
||||
qr/starting_upsert_s2/, q[ |
||||
\echo starting_upsert_s2 |
||||
INSERT INTO test.tblpk VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
# Wait for s2 to hit injection point |
||||
ok_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
# Wakeup s1 (check-exclusion-or-unique-constraint-no-conflict) |
||||
wakeup_injection_point($node, |
||||
'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
# Wakeup s2 (exec-insert-before-insert-speculative) |
||||
wakeup_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
clean_safe_quit_ok($s1, $s2, $s3); |
||||
|
||||
# Cleanup test 1 |
||||
$node->safe_psql('postgres', 'TRUNCATE TABLE test.tblpk'); |
||||
|
||||
############################################################################ |
||||
note('Test: REINDEX CONCURRENTLY + UPSERT (wakeup at swap phase)'); |
||||
|
||||
$s1 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s2 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s3 = $node->background_psql('postgres', on_error_stop => 0); |
||||
|
||||
$s1->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
]); |
||||
|
||||
$s2->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-swap', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_until( |
||||
qr/starting_reindex/, q[ |
||||
\echo starting_reindex |
||||
REINDEX INDEX CONCURRENTLY test.tblpk_pkey; |
||||
]); |
||||
|
||||
ok_injection_point($node, 'reindex-relation-concurrently-before-swap'); |
||||
|
||||
$s1->query_until( |
||||
qr/starting_upsert_s1/, q[ |
||||
\echo starting_upsert_s1 |
||||
INSERT INTO test.tblpk VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
wakeup_injection_point($node, 'reindex-relation-concurrently-before-swap'); |
||||
|
||||
$s2->query_until( |
||||
qr/starting_upsert_s2/, q[ |
||||
\echo starting_upsert_s2 |
||||
INSERT INTO test.tblpk VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
wakeup_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
wakeup_injection_point($node, |
||||
'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
clean_safe_quit_ok($s1, $s2, $s3); |
||||
|
||||
$node->safe_psql('postgres', 'TRUNCATE TABLE test.tblpk'); |
||||
|
||||
############################################################################ |
||||
note('Test: REINDEX CONCURRENTLY + UPSERT (s1 wakes before reindex)'); |
||||
|
||||
$s1 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s2 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s3 = $node->background_psql('postgres', on_error_stop => 0); |
||||
|
||||
$s1->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
]); |
||||
|
||||
$s2->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_until( |
||||
qr/starting_reindex/, q[ |
||||
\echo starting_reindex |
||||
REINDEX INDEX CONCURRENTLY test.tblpk_pkey; |
||||
]); |
||||
|
||||
ok_injection_point($node, 'reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
$s1->query_until( |
||||
qr/starting_upsert_s1/, q[ |
||||
\echo starting_upsert_s1 |
||||
INSERT INTO test.tblpk VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
# Start s2 BEFORE waking reindex (key difference from permutation 1) |
||||
$s2->query_until( |
||||
qr/starting_upsert_s2/, q[ |
||||
\echo starting_upsert_s2 |
||||
INSERT INTO test.tblpk VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
# Wake s1 first, then reindex, then s2 |
||||
wakeup_injection_point($node, |
||||
'check-exclusion-or-unique-constraint-no-conflict'); |
||||
wakeup_injection_point($node, |
||||
'reindex-relation-concurrently-before-set-dead'); |
||||
wakeup_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
clean_safe_quit_ok($s1, $s2, $s3); |
||||
|
||||
$node->safe_psql('postgres', 'TRUNCATE TABLE test.tblpk'); |
||||
|
||||
############################################################################ |
||||
note('Test: REINDEX + UPSERT ON CONSTRAINT (set-dead phase)'); |
||||
|
||||
$s1 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s2 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s3 = $node->background_psql('postgres', on_error_stop => 0); |
||||
|
||||
$s1->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
]); |
||||
|
||||
$s2->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_until( |
||||
qr/starting_reindex/, q[ |
||||
\echo starting_reindex |
||||
REINDEX INDEX CONCURRENTLY test.tblpk_pkey; |
||||
]); |
||||
|
||||
ok_injection_point($node, 'reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
$s1->query_until( |
||||
qr/starting_upsert_s1/, q[ |
||||
\echo starting_upsert_s1 |
||||
INSERT INTO test.tblpk VALUES (13, now()) ON CONFLICT ON CONSTRAINT tblpk_pkey DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
wakeup_injection_point($node, |
||||
'reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
$s2->query_until( |
||||
qr/starting_upsert_s2/, q[ |
||||
\echo starting_upsert_s2 |
||||
INSERT INTO test.tblpk VALUES (13, now()) ON CONFLICT ON CONSTRAINT tblpk_pkey DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
wakeup_injection_point($node, |
||||
'check-exclusion-or-unique-constraint-no-conflict'); |
||||
wakeup_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
clean_safe_quit_ok($s1, $s2, $s3); |
||||
|
||||
$node->safe_psql('postgres', 'TRUNCATE TABLE test.tblpk'); |
||||
|
||||
############################################################################ |
||||
note('Test: REINDEX + UPSERT ON CONSTRAINT (swap phase)'); |
||||
|
||||
$s1 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s2 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s3 = $node->background_psql('postgres', on_error_stop => 0); |
||||
|
||||
$s1->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
]); |
||||
|
||||
$s2->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-swap', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_until( |
||||
qr/starting_reindex/, q[ |
||||
\echo starting_reindex |
||||
REINDEX INDEX CONCURRENTLY test.tblpk_pkey; |
||||
]); |
||||
|
||||
ok_injection_point($node, 'reindex-relation-concurrently-before-swap'); |
||||
|
||||
$s1->query_until( |
||||
qr/starting_upsert_s1/, q[ |
||||
\echo starting_upsert_s1 |
||||
INSERT INTO test.tblpk VALUES (13, now()) ON CONFLICT ON CONSTRAINT tblpk_pkey DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
wakeup_injection_point($node, 'reindex-relation-concurrently-before-swap'); |
||||
|
||||
$s2->query_until( |
||||
qr/starting_upsert_s2/, q[ |
||||
\echo starting_upsert_s2 |
||||
INSERT INTO test.tblpk VALUES (13, now()) ON CONFLICT ON CONSTRAINT tblpk_pkey DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
wakeup_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
wakeup_injection_point($node, |
||||
'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
clean_safe_quit_ok($s1, $s2, $s3); |
||||
|
||||
$node->safe_psql('postgres', 'TRUNCATE TABLE test.tblpk'); |
||||
|
||||
############################################################################ |
||||
note('Test: REINDEX + UPSERT ON CONSTRAINT (s1 wakes before reindex)'); |
||||
|
||||
$s1 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s2 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s3 = $node->background_psql('postgres', on_error_stop => 0); |
||||
|
||||
$s1->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
]); |
||||
|
||||
$s2->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_until( |
||||
qr/starting_reindex/, q[ |
||||
\echo starting_reindex |
||||
REINDEX INDEX CONCURRENTLY test.tblpk_pkey; |
||||
]); |
||||
|
||||
ok_injection_point($node, 'reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
$s1->query_until( |
||||
qr/starting_upsert_s1/, q[ |
||||
\echo starting_upsert_s1 |
||||
INSERT INTO test.tblpk VALUES (13, now()) ON CONFLICT ON CONSTRAINT tblpk_pkey DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
# Start s2 BEFORE waking reindex |
||||
$s2->query_until( |
||||
qr/starting_upsert_s2/, q[ |
||||
\echo starting_upsert_s2 |
||||
INSERT INTO test.tblpk VALUES (13, now()) ON CONFLICT ON CONSTRAINT tblpk_pkey DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
# Wake s1 first, then reindex, then s2 |
||||
wakeup_injection_point($node, |
||||
'check-exclusion-or-unique-constraint-no-conflict'); |
||||
wakeup_injection_point($node, |
||||
'reindex-relation-concurrently-before-set-dead'); |
||||
wakeup_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
clean_safe_quit_ok($s1, $s2, $s3); |
||||
|
||||
$node->safe_psql('postgres', 'TRUNCATE TABLE test.tblpk'); |
||||
|
||||
############################################################################ |
||||
note('Test: REINDEX on partitioned table (set-dead phase)'); |
||||
|
||||
$s1 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s2 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s3 = $node->background_psql('postgres', on_error_stop => 0); |
||||
|
||||
$s1->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
]); |
||||
|
||||
$s2->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_until( |
||||
qr/starting_reindex/, q[ |
||||
\echo starting_reindex |
||||
REINDEX INDEX CONCURRENTLY test.tbl_partition_pkey; |
||||
]); |
||||
|
||||
ok_injection_point($node, 'reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
$s1->query_until( |
||||
qr/starting_upsert_s1/, q[ |
||||
\echo starting_upsert_s1 |
||||
INSERT INTO test.tblparted VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
wakeup_injection_point($node, |
||||
'reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
$s2->query_until( |
||||
qr/starting_upsert_s2/, q[ |
||||
\echo starting_upsert_s2 |
||||
INSERT INTO test.tblparted VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
wakeup_injection_point($node, |
||||
'check-exclusion-or-unique-constraint-no-conflict'); |
||||
wakeup_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
clean_safe_quit_ok($s1, $s2, $s3); |
||||
|
||||
$node->safe_psql('postgres', 'TRUNCATE TABLE test.tblparted'); |
||||
|
||||
############################################################################ |
||||
note('Test: REINDEX on partitioned table (swap phase)'); |
||||
|
||||
$s1 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s2 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s3 = $node->background_psql('postgres', on_error_stop => 0); |
||||
|
||||
$s1->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
]); |
||||
|
||||
$s2->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-swap', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_until( |
||||
qr/starting_reindex/, q[ |
||||
\echo starting_reindex |
||||
REINDEX INDEX CONCURRENTLY test.tbl_partition_pkey; |
||||
]); |
||||
|
||||
ok_injection_point($node, 'reindex-relation-concurrently-before-swap'); |
||||
|
||||
$s1->query_until( |
||||
qr/starting_upsert_s1/, q[ |
||||
\echo starting_upsert_s1 |
||||
INSERT INTO test.tblparted VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
wakeup_injection_point($node, 'reindex-relation-concurrently-before-swap'); |
||||
|
||||
$s2->query_until( |
||||
qr/starting_upsert_s2/, q[ |
||||
\echo starting_upsert_s2 |
||||
INSERT INTO test.tblparted VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
wakeup_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
wakeup_injection_point($node, |
||||
'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
clean_safe_quit_ok($s1, $s2, $s3); |
||||
|
||||
$node->safe_psql('postgres', 'TRUNCATE TABLE test.tblparted'); |
||||
|
||||
############################################################################ |
||||
note('Test: REINDEX on partitioned table (s1 wakes before reindex)'); |
||||
|
||||
$s1 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s2 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s3 = $node->background_psql('postgres', on_error_stop => 0); |
||||
|
||||
$s1->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
]); |
||||
|
||||
$s2->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('reindex-relation-concurrently-before-set-dead', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_until( |
||||
qr/starting_reindex/, q[ |
||||
\echo starting_reindex |
||||
REINDEX INDEX CONCURRENTLY test.tbl_partition_pkey; |
||||
]); |
||||
|
||||
ok_injection_point($node, 'reindex-relation-concurrently-before-set-dead'); |
||||
|
||||
$s1->query_until( |
||||
qr/starting_upsert_s1/, q[ |
||||
\echo starting_upsert_s1 |
||||
INSERT INTO test.tblparted VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
# Start s2 BEFORE waking reindex |
||||
$s2->query_until( |
||||
qr/starting_upsert_s2/, q[ |
||||
\echo starting_upsert_s2 |
||||
INSERT INTO test.tblparted VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
# Wake s1 first, then reindex, then s2 |
||||
wakeup_injection_point($node, |
||||
'check-exclusion-or-unique-constraint-no-conflict'); |
||||
wakeup_injection_point($node, |
||||
'reindex-relation-concurrently-before-set-dead'); |
||||
wakeup_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
clean_safe_quit_ok($s1, $s2, $s3); |
||||
|
||||
$node->safe_psql('postgres', 'TRUNCATE TABLE test.tblparted'); |
||||
|
||||
############################################################################ |
||||
note('Test: CREATE INDEX CONCURRENTLY + UPSERT'); |
||||
# Uses invalidate-catalog-snapshot-end to test catalog invalidation |
||||
# during UPSERT |
||||
|
||||
$s1 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s2 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s3 = $node->background_psql('postgres', on_error_stop => 0); |
||||
|
||||
my $s1_pid = $s1->query_safe('SELECT pg_backend_pid()'); |
||||
|
||||
# s1 attaches BOTH injection points - the unique constraint check AND catalog snapshot |
||||
$s1->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
]); |
||||
|
||||
$s1->query_until( |
||||
qr/attaching_injection_point/, q[ |
||||
\echo attaching_injection_point |
||||
SELECT injection_points_attach('invalidate-catalog-snapshot-end', 'wait'); |
||||
]); |
||||
# In case of CLOBBER_CACHE_ALWAYS - s1 may hit the injection point during attach. |
||||
# Wait for s1 to become idle (attach completed) or wakeup if stuck on injection point. |
||||
if (!wait_for_idle($node, $s1_pid)) |
||||
{ |
||||
ok_injection_point( |
||||
$node, |
||||
'invalidate-catalog-snapshot-end', |
||||
's1 hit injection point during attach (CLOBBER_CACHE_ALWAYS)'); |
||||
$node->safe_psql( |
||||
'postgres', q[ |
||||
SELECT injection_points_wakeup('invalidate-catalog-snapshot-end'); |
||||
]); |
||||
} |
||||
|
||||
$s2->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('define-index-before-set-valid', 'wait'); |
||||
]); |
||||
|
||||
# s3: Start CREATE INDEX CONCURRENTLY (blocks on define-index-before-set-valid) |
||||
$s3->query_until( |
||||
qr/starting_create_index/, q[ |
||||
\echo starting_create_index |
||||
CREATE UNIQUE INDEX CONCURRENTLY tbl_pkey_duplicate ON test.tblpk(i); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'define-index-before-set-valid'); |
||||
|
||||
# s1: Start UPSERT (blocks on invalidate-catalog-snapshot-end) |
||||
$s1->query_until( |
||||
qr/starting_upsert_s1/, q[ |
||||
\echo starting_upsert_s1 |
||||
INSERT INTO test.tblpk VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'invalidate-catalog-snapshot-end'); |
||||
|
||||
# Wakeup s3 (CREATE INDEX continues, triggers catalog invalidation) |
||||
wakeup_injection_point($node, 'define-index-before-set-valid'); |
||||
|
||||
# s2: Start UPSERT (blocks on exec-insert-before-insert-speculative) |
||||
$s2->query_until( |
||||
qr/starting_upsert_s2/, q[ |
||||
\echo starting_upsert_s2 |
||||
INSERT INTO test.tblpk VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
wakeup_injection_point($node, 'invalidate-catalog-snapshot-end'); |
||||
|
||||
ok_injection_point($node, 'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
wakeup_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
|
||||
wakeup_injection_point($node, |
||||
'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
clean_safe_quit_ok($s1, $s2, $s3); |
||||
|
||||
$node->safe_psql('postgres', 'TRUNCATE TABLE test.tblparted'); |
||||
|
||||
############################################################################ |
||||
note('Test: CREATE INDEX CONCURRENTLY on partial index + UPSERT'); |
||||
# Uses invalidate-catalog-snapshot-end to test catalog invalidation during UPSERT |
||||
|
||||
$s1 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s2 = $node->background_psql('postgres', on_error_stop => 0); |
||||
$s3 = $node->background_psql('postgres', on_error_stop => 0); |
||||
|
||||
$s1_pid = $s1->query_safe('SELECT pg_backend_pid()'); |
||||
|
||||
# s1 attaches BOTH injection points - the unique constraint check AND catalog snapshot |
||||
$s1->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('check-exclusion-or-unique-constraint-no-conflict', 'wait'); |
||||
]); |
||||
|
||||
$s1->query_until( |
||||
qr/attaching_injection_point/, q[ |
||||
\echo attaching_injection_point |
||||
SELECT injection_points_attach('invalidate-catalog-snapshot-end', 'wait'); |
||||
]); |
||||
# In case of CLOBBER_CACHE_ALWAYS - s1 may hit the injection point during attach. |
||||
# Wait for s1 to become idle (attach completed) or wakeup if stuck on injection point. |
||||
if (!wait_for_idle($node, $s1_pid)) |
||||
{ |
||||
ok_injection_point($node, 'invalidate-catalog-snapshot-end', |
||||
'Test 8: s1 hit injection point during attach (CLOBBER_CACHE_ALWAYS)' |
||||
); |
||||
$node->safe_psql( |
||||
'postgres', q[ |
||||
SELECT injection_points_wakeup('invalidate-catalog-snapshot-end'); |
||||
]); |
||||
} |
||||
|
||||
$s2->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('exec-insert-before-insert-speculative', 'wait'); |
||||
]); |
||||
|
||||
$s3->query_safe( |
||||
q[ |
||||
SELECT injection_points_set_local(); |
||||
SELECT injection_points_attach('define-index-before-set-valid', 'wait'); |
||||
]); |
||||
|
||||
# s3: Start CREATE INDEX CONCURRENTLY (blocks on define-index-before-set-valid) |
||||
$s3->query_until( |
||||
qr/starting_create_index/, q[ |
||||
\echo starting_create_index |
||||
CREATE UNIQUE INDEX CONCURRENTLY tbl_pkey_special_duplicate ON test.tblexpr(abs(i)) WHERE i < 10000; |
||||
]); |
||||
|
||||
ok_injection_point($node, 'define-index-before-set-valid'); |
||||
|
||||
# s1: Start UPSERT (blocks on invalidate-catalog-snapshot-end) |
||||
$s1->query_until( |
||||
qr/starting_upsert_s1/, q[ |
||||
\echo starting_upsert_s1 |
||||
INSERT INTO test.tblexpr VALUES(13,now()) ON CONFLICT (abs(i)) WHERE i < 100 DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'invalidate-catalog-snapshot-end'); |
||||
|
||||
# Wakeup s3 (CREATE INDEX continues, triggers catalog invalidation) |
||||
wakeup_injection_point($node, 'define-index-before-set-valid'); |
||||
|
||||
# s2: Start UPSERT (blocks on exec-insert-before-insert-speculative) |
||||
$s2->query_until( |
||||
qr/starting_upsert_s2/, q[ |
||||
\echo starting_upsert_s2 |
||||
INSERT INTO test.tblexpr VALUES(13,now()) ON CONFLICT (abs(i)) WHERE i < 100 DO UPDATE SET updated_at = now(); |
||||
]); |
||||
|
||||
ok_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
wakeup_injection_point($node, 'invalidate-catalog-snapshot-end'); |
||||
ok_injection_point($node, 'check-exclusion-or-unique-constraint-no-conflict'); |
||||
wakeup_injection_point($node, 'exec-insert-before-insert-speculative'); |
||||
wakeup_injection_point($node, |
||||
'check-exclusion-or-unique-constraint-no-conflict'); |
||||
|
||||
clean_safe_quit_ok($s1, $s2, $s3); |
||||
|
||||
$node->safe_psql('postgres', 'TRUNCATE TABLE test.tblexpr'); |
||||
|
||||
done_testing(); |
||||
|
||||
############################################################################ |
||||
# Helper functions |
||||
# |
||||
############################################################################ |
||||
|
||||
# Helper: Wait for a session to hit an injection point. |
||||
# Optional second argument is timeout in seconds. |
||||
# Returns true if found, false if timeout. |
||||
# On timeout, logs diagnostic information about all active queries. |
||||
sub wait_for_injection_point |
||||
{ |
||||
my ($node, $point_name, $timeout) = @_; |
||||
$timeout //= $PostgreSQL::Test::Utils::timeout_default; |
||||
|
||||
for (my $elapsed = 0; $elapsed < $timeout * 10; $elapsed++) |
||||
{ |
||||
my $pid = $node->safe_psql( |
||||
'postgres', qq[ |
||||
SELECT pid FROM pg_stat_activity |
||||
WHERE wait_event_type = 'InjectionPoint' |
||||
AND wait_event = '$point_name' |
||||
LIMIT 1; |
||||
]); |
||||
return 1 if $pid ne ''; |
||||
sleep(0.1); |
||||
} |
||||
|
||||
# Timeout - report diagnostic information |
||||
my $activity = $node->safe_psql( |
||||
'postgres', q[ |
||||
SELECT format('pid=%s, state=%s, wait_event_type=%s, wait_event=%s, backend_xmin=%s, backend_xid=%s, query=%s', |
||||
pid, state, wait_event_type, wait_event, backend_xmin, backend_xid, left(query, 100)) |
||||
FROM pg_stat_activity |
||||
ORDER BY pid; |
||||
]); |
||||
diag( "wait_for_injection_point timeout waiting for: $point_name\n" |
||||
. "Current queries in pg_stat_activity:\n$activity"); |
||||
|
||||
return 0; |
||||
} |
||||
|
||||
# Test helper: ok() a wait for the given injection point |
||||
# Third argument is an optional test name. |
||||
sub ok_injection_point |
||||
{ |
||||
my ($node, $injection_point, $testname) = @_; |
||||
$testname //= "hit injection point $injection_point"; |
||||
|
||||
ok(wait_for_injection_point($node, $injection_point), $testname); |
||||
} |
||||
|
||||
# Helper: Wait for a specific backend to become idle. |
||||
# Returns true if idle, false if timeout. |
||||
sub wait_for_idle |
||||
{ |
||||
my ($node, $pid, $timeout) = @_; |
||||
$timeout //= $PostgreSQL::Test::Utils::timeout_default; |
||||
|
||||
for (my $elapsed = 0; $elapsed < $timeout * 10; $elapsed++) |
||||
{ |
||||
my $state = $node->safe_psql( |
||||
'postgres', qq[ |
||||
SELECT state FROM pg_stat_activity WHERE pid = $pid; |
||||
]); |
||||
return 1 if $state eq 'idle'; |
||||
sleep(0.1); |
||||
} |
||||
return 0; |
||||
} |
||||
|
||||
# Helper: Detach and wakeup an injection point |
||||
sub wakeup_injection_point |
||||
{ |
||||
my ($node, $point_name) = @_; |
||||
$node->safe_psql( |
||||
'postgres', qq[ |
||||
SELECT injection_points_detach('$point_name'); |
||||
SELECT injection_points_wakeup('$point_name'); |
||||
]); |
||||
} |
||||
|
||||
# Wait for any pending query to complete, capture stderr, and close the session. |
||||
# Returns the stderr output (excluding internal markers). |
||||
sub safe_quit |
||||
{ |
||||
my ($session) = @_; |
||||
|
||||
# Send a marker and wait for it to ensure any pending query completes |
||||
my $banner = "safe_quit_marker"; |
||||
my $banner_match = qr/(^|\n)$banner\r?\n/; |
||||
|
||||
$session->{stdin} .= "\\echo $banner\n\\warn $banner\n"; |
||||
|
||||
pump_until( |
||||
$session->{run}, $session->{timeout}, |
||||
\$session->{stdout}, $banner_match); |
||||
pump_until( |
||||
$session->{run}, $session->{timeout}, |
||||
\$session->{stderr}, $banner_match); |
||||
|
||||
# Capture stderr (excluding the banner) |
||||
my $stderr = $session->{stderr}; |
||||
$stderr =~ s/$banner_match//; |
||||
|
||||
# Close the session |
||||
$session->quit; |
||||
|
||||
return $stderr; |
||||
} |
||||
|
||||
# Helper function: verify that the given sessions exit cleanly. |
||||
sub clean_safe_quit_ok |
||||
{ |
||||
my $i = 1; |
||||
foreach my $session (@_) |
||||
{ |
||||
is(safe_quit($session), '', "session " . $i++ . " quit cleanly"); |
||||
} |
||||
} |
||||
Loading…
Reference in new issue