mirror of
https://github.com/postgres/postgres.git
synced 2026-01-14 02:01:53 +00:00
Replace flaky CIC/RI isolation tests with a TAP test
The isolation tests for INSERT ON CONFLICT behavior during CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY (added bybc32a12e0d,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
This commit is contained in:
@ -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
|
||||
|
||||
|
||||
@ -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>
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
@ -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
|
||||
|
||||
@ -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,
|
||||
},
|
||||
}
|
||||
|
||||
902
src/test/modules/test_misc/t/010_index_concurrently_upsert.pl
Normal file
902
src/test/modules/test_misc/t/010_index_concurrently_upsert.pl
Normal file
@ -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");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user