diff --git a/src/test/modules/injection_points/Makefile b/src/test/modules/injection_points/Makefile index cc9be6dcdd2..a41d781f8c9 100644 --- a/src/test/modules/injection_points/Makefile +++ b/src/test/modules/injection_points/Makefile @@ -17,14 +17,6 @@ ISOLATION = basic \ syscache-update-pruned \ heap_lock_update -# Temporarily disabled because of flakiness -#ISOLATION =+ -# index-concurrently-upsert \ -# index-concurrently-upsert-predicate \ -# reindex-concurrently-upsert \ -# reindex-concurrently-upsert-on-constraint \ -# reindex-concurrently-upsert-partitioned - # The injection points are cluster-wide, so disable installcheck NO_INSTALLCHECK = 1 diff --git a/src/test/modules/injection_points/expected/index-concurrently-upsert-predicate.out b/src/test/modules/injection_points/expected/index-concurrently-upsert-predicate.out deleted file mode 100644 index 77e7d1a7815..00000000000 --- a/src/test/modules/injection_points/expected/index-concurrently-upsert-predicate.out +++ /dev/null @@ -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; - -step s1_start_upsert: - INSERT INTO test.tbl VALUES(13,now()) ON CONFLICT (abs(i)) WHERE i < 100 DO UPDATE SET updated_at = now(); - -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(); - -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> diff --git a/src/test/modules/injection_points/expected/index-concurrently-upsert-predicate_1.out b/src/test/modules/injection_points/expected/index-concurrently-upsert-predicate_1.out deleted file mode 100644 index e72848d6a78..00000000000 --- a/src/test/modules/injection_points/expected/index-concurrently-upsert-predicate_1.out +++ /dev/null @@ -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'); - -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; - -step s1_start_upsert: - INSERT INTO test.tbl VALUES(13,now()) ON CONFLICT (abs(i)) WHERE i < 100 DO UPDATE SET updated_at = now(); - -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(); - -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> diff --git a/src/test/modules/injection_points/expected/index-concurrently-upsert.out b/src/test/modules/injection_points/expected/index-concurrently-upsert.out deleted file mode 100644 index a2ef122625c..00000000000 --- a/src/test/modules/injection_points/expected/index-concurrently-upsert.out +++ /dev/null @@ -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); - -step s1_start_upsert: - INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); - -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(); - -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> diff --git a/src/test/modules/injection_points/expected/index-concurrently-upsert_1.out b/src/test/modules/injection_points/expected/index-concurrently-upsert_1.out deleted file mode 100644 index ee3b6641b90..00000000000 --- a/src/test/modules/injection_points/expected/index-concurrently-upsert_1.out +++ /dev/null @@ -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'); - -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); - -step s1_start_upsert: - INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); - -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(); - -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> diff --git a/src/test/modules/injection_points/expected/reindex-concurrently-upsert-on-constraint.out b/src/test/modules/injection_points/expected/reindex-concurrently-upsert-on-constraint.out deleted file mode 100644 index c1ac1f77c61..00000000000 --- a/src/test/modules/injection_points/expected/reindex-concurrently-upsert-on-constraint.out +++ /dev/null @@ -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; - -step s1_start_upsert: - INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT ON CONSTRAINT tbl_pkey DO UPDATE SET updated_at = now(); - -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(); - -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; - -step s1_start_upsert: - INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT ON CONSTRAINT tbl_pkey DO UPDATE SET updated_at = now(); - -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(); - -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; - -step s1_start_upsert: - INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT ON CONSTRAINT tbl_pkey DO UPDATE SET updated_at = now(); - -step s2_start_upsert: - INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT ON CONSTRAINT tbl_pkey DO UPDATE SET updated_at = now(); - -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> diff --git a/src/test/modules/injection_points/expected/reindex-concurrently-upsert-partitioned.out b/src/test/modules/injection_points/expected/reindex-concurrently-upsert-partitioned.out deleted file mode 100644 index 4c79a43d986..00000000000 --- a/src/test/modules/injection_points/expected/reindex-concurrently-upsert-partitioned.out +++ /dev/null @@ -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; - -step s1_start_upsert: - INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); - -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(); - -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; - -step s1_start_upsert: - INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); - -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(); - -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; - -step s1_start_upsert: - INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); - -step s2_start_upsert: - INSERT INTO test.tbl VALUES (13, now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); - -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> diff --git a/src/test/modules/injection_points/expected/reindex-concurrently-upsert.out b/src/test/modules/injection_points/expected/reindex-concurrently-upsert.out deleted file mode 100644 index c9cc9989d02..00000000000 --- a/src/test/modules/injection_points/expected/reindex-concurrently-upsert.out +++ /dev/null @@ -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; - -step s1_start_upsert: - INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); - -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(); - -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; - -step s1_start_upsert: - INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); - -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(); - -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; - -step s1_start_upsert: - INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); - -step s2_start_upsert: - INSERT INTO test.tbl VALUES (13,now()) ON CONFLICT (i) DO UPDATE SET updated_at = now(); - -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> diff --git a/src/test/modules/injection_points/meson.build b/src/test/modules/injection_points/meson.build index 456ef3ed3de..fcc85414515 100644 --- a/src/test/modules/injection_points/meson.build +++ b/src/test/modules/injection_points/meson.build @@ -47,12 +47,6 @@ tests += { 'inplace', 'syscache-update-pruned', 'heap_lock_update', - # temporarily disabled because of flakiness - # 'index-concurrently-upsert', - # 'index-concurrently-upsert-predicate', - # 'reindex-concurrently-upsert', - # 'reindex-concurrently-upsert-on-constraint', - # 'reindex-concurrently-upsert-partitioned', ], 'runningcheck': false, # see syscache-update-pruned # Some tests wait for all snapshots, so avoid parallel execution diff --git a/src/test/modules/injection_points/specs/index-concurrently-upsert-predicate.spec b/src/test/modules/injection_points/specs/index-concurrently-upsert-predicate.spec deleted file mode 100644 index d9b8d27fd1f..00000000000 --- a/src/test/modules/injection_points/specs/index-concurrently-upsert-predicate.spec +++ /dev/null @@ -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 diff --git a/src/test/modules/injection_points/specs/index-concurrently-upsert.spec b/src/test/modules/injection_points/specs/index-concurrently-upsert.spec deleted file mode 100644 index 6e08af74a93..00000000000 --- a/src/test/modules/injection_points/specs/index-concurrently-upsert.spec +++ /dev/null @@ -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 diff --git a/src/test/modules/injection_points/specs/reindex-concurrently-upsert-on-constraint.spec b/src/test/modules/injection_points/specs/reindex-concurrently-upsert-on-constraint.spec deleted file mode 100644 index 4bbdda3cf04..00000000000 --- a/src/test/modules/injection_points/specs/reindex-concurrently-upsert-on-constraint.spec +++ /dev/null @@ -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 diff --git a/src/test/modules/injection_points/specs/reindex-concurrently-upsert-partitioned.spec b/src/test/modules/injection_points/specs/reindex-concurrently-upsert-partitioned.spec deleted file mode 100644 index c3504b9ef38..00000000000 --- a/src/test/modules/injection_points/specs/reindex-concurrently-upsert-partitioned.spec +++ /dev/null @@ -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 diff --git a/src/test/modules/injection_points/specs/reindex-concurrently-upsert.spec b/src/test/modules/injection_points/specs/reindex-concurrently-upsert.spec deleted file mode 100644 index 1b043a48ff4..00000000000 --- a/src/test/modules/injection_points/specs/reindex-concurrently-upsert.spec +++ /dev/null @@ -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 diff --git a/src/test/modules/test_misc/Makefile b/src/test/modules/test_misc/Makefile index 399b9094a38..fedbef071ef 100644 --- a/src/test/modules/test_misc/Makefile +++ b/src/test/modules/test_misc/Makefile @@ -5,6 +5,9 @@ TAP_TESTS = 1 EXTRA_INSTALL=src/test/modules/injection_points \ contrib/test_decoding +# The injection points are cluster-wide, so disable installcheck +NO_INSTALLCHECK = 1 + export enable_injection_points ifdef USE_PGXS diff --git a/src/test/modules/test_misc/meson.build b/src/test/modules/test_misc/meson.build index d08201cb977..6e8db1621a7 100644 --- a/src/test/modules/test_misc/meson.build +++ b/src/test/modules/test_misc/meson.build @@ -18,6 +18,9 @@ tests += { 't/007_catcache_inval.pl', 't/008_replslot_single_user.pl', 't/009_log_temp_files.pl', + 't/010_index_concurrently_upsert.pl', ], + # The injection points are cluster-wide, so disable installcheck + 'runningcheck': false, }, } diff --git a/src/test/modules/test_misc/t/010_index_concurrently_upsert.pl b/src/test/modules/test_misc/t/010_index_concurrently_upsert.pl new file mode 100644 index 00000000000..5953af11e9e --- /dev/null +++ b/src/test/modules/test_misc/t/010_index_concurrently_upsert.pl @@ -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"); + } +}