Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit e621150

Browse files
michail-nikolaevCommitfest Bot
authored and
Commitfest Bot
committed
Specs to reproduce the issues with CREATE INDEX CONCURRENTLY and REINDEX CONCURRENTLY in scenarios involving INSERT ON CONFLICT DO UPDATE. These tests reproduce different error cases related to "duplicate key value violates unique constraint" where this error should not occur by design.
* REINDEX CONCURRENTLY and UPSERT with inferred index * CREATE INDEX CONCURRENTLY and UPSERT with inferred indexes * REINDEX CONCURRENTLY on a partitioned table * REINDEX CONCURRENTLY with specified constraint name * CREATE INDEX CONCURRENTLY with predicates In each of these scenarios, the expected behavior is that the INSERT ON CONFLICT DO UPDATE should handle conflicts gracefully without raising a "duplicate key value violates unique constraint" error. However, due to the concurrent operations on the indexes, this error is encountered.
1 parent 470273d commit e621150

16 files changed

+1361
-2
lines changed

src/backend/commands/indexcmds.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1790,6 +1790,7 @@ DefineIndex(Oid tableId,
17901790
* before the reference snap was taken, we have to wait out any
17911791
* transactions that might have older snapshots.
17921792
*/
1793+
INJECTION_POINT("define_index_before_set_valid", NULL);
17931794
pgstat_progress_update_param(PROGRESS_CREATEIDX_PHASE,
17941795
PROGRESS_CREATEIDX_PHASE_WAIT_3);
17951796
WaitForOlderSnapshots(limitXmin, true);
@@ -4195,7 +4196,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
41954196
* the same time to make sure we only get constraint violations from the
41964197
* indexes with the correct names.
41974198
*/
4198-
4199+
INJECTION_POINT("reindex_relation_concurrently_before_swap", NULL);
41994200
StartTransactionCommand();
42004201

42014202
/*
@@ -4274,6 +4275,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
42744275
* index_drop() for more details.
42754276
*/
42764277

4278+
INJECTION_POINT("reindex_relation_concurrently_before_set_dead", NULL);
42774279
pgstat_progress_update_param(PROGRESS_CREATEIDX_PHASE,
42784280
PROGRESS_CREATEIDX_PHASE_WAIT_4);
42794281
WaitForLockersMultiple(lockTags, AccessExclusiveLock, true);

src/backend/executor/execIndexing.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -117,6 +117,7 @@
117117
#include "utils/multirangetypes.h"
118118
#include "utils/rangetypes.h"
119119
#include "utils/snapmgr.h"
120+
#include "utils/injection_point.h"
120121

121122
/* waitMode argument to check_exclusion_or_unique_constraint() */
122123
typedef enum
@@ -942,6 +943,8 @@ check_exclusion_or_unique_constraint(Relation heap, Relation index,
942943
econtext->ecxt_scantuple = save_scantuple;
943944

944945
ExecDropSingleTupleTableSlot(existing_slot);
946+
if (!conflict)
947+
INJECTION_POINT("check_exclusion_or_unique_constraint_no_conflict", NULL);
945948

946949
return !conflict;
947950
}

src/backend/executor/nodeModifyTable.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@
6969
#include "utils/datum.h"
7070
#include "utils/rel.h"
7171
#include "utils/snapmgr.h"
72+
#include "utils/injection_point.h"
7273

7374

7475
typedef struct MTTargetRelLookup
@@ -1178,6 +1179,7 @@ ExecInsert(ModifyTableContext *context,
11781179
return NULL;
11791180
}
11801181
}
1182+
INJECTION_POINT("exec_insert_before_insert_speculative", NULL);
11811183

11821184
/*
11831185
* Before we start insertion proper, acquire our "speculative

src/backend/utils/time/snapmgr.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@
123123
#include "utils/resowner.h"
124124
#include "utils/snapmgr.h"
125125
#include "utils/syscache.h"
126+
#include "utils/injection_point.h"
126127

127128

128129
/*
@@ -447,6 +448,7 @@ InvalidateCatalogSnapshot(void)
447448
pairingheap_remove(&RegisteredSnapshots, &CatalogSnapshot->ph_node);
448449
CatalogSnapshot = NULL;
449450
SnapshotResetXmin();
451+
INJECTION_POINT("invalidate_catalog_snapshot_end", NULL);
450452
}
451453
}
452454

src/test/modules/injection_points/Makefile

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,12 @@ PGFILEDESC = "injection_points - facility for injection points"
1414
REGRESS = injection_points hashagg reindex_conc
1515
REGRESS_OPTS = --dlpath=$(top_builddir)/src/test/regress
1616

17-
ISOLATION = basic inplace syscache-update-pruned
17+
ISOLATION = basic inplace syscache-update-pruned \
18+
reindex_concurrently_upsert \
19+
index_concurrently_upsert \
20+
reindex_concurrently_upsert_partitioned \
21+
reindex_concurrently_upsert_on_constraint \
22+
index_concurrently_upsert_predicate
1823

1924
TAP_TESTS = 1
2025

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
Parsed test spec with 4 sessions
2+
3+
starting permutation: s3_start_create_index s1_start_upsert s4_wakeup_define_index_before_set_valid s2_start_upsert s4_wakeup_s1_from_invalidate_catalog_snapshot s4_wakeup_s2 s4_wakeup_s1
4+
injection_points_attach
5+
-----------------------
6+
7+
(1 row)
8+
9+
injection_points_attach
10+
-----------------------
11+
12+
(1 row)
13+
14+
injection_points_attach
15+
-----------------------
16+
17+
(1 row)
18+
19+
step s3_start_create_index: CREATE UNIQUE INDEX CONCURRENTLY tbl_pkey_duplicate ON test.tbl(i); <waiting ...>
20+
step s1_start_upsert:
21+
INSERT INTO test.tbl VALUES(13,now()) on conflict(i) do update set updated_at = now();
22+
<waiting ...>
23+
step s4_wakeup_define_index_before_set_valid:
24+
SELECT injection_points_detach('define_index_before_set_valid');
25+
SELECT injection_points_wakeup('define_index_before_set_valid');
26+
27+
injection_points_detach
28+
-----------------------
29+
30+
(1 row)
31+
32+
injection_points_wakeup
33+
-----------------------
34+
35+
(1 row)
36+
37+
step s2_start_upsert:
38+
INSERT INTO test.tbl VALUES(13,now()) on conflict(i) do update set updated_at = now();
39+
<waiting ...>
40+
step s4_wakeup_s1_from_invalidate_catalog_snapshot:
41+
SELECT injection_points_detach('invalidate_catalog_snapshot_end');
42+
SELECT injection_points_wakeup('invalidate_catalog_snapshot_end');
43+
44+
injection_points_detach
45+
-----------------------
46+
47+
(1 row)
48+
49+
injection_points_wakeup
50+
-----------------------
51+
52+
(1 row)
53+
54+
step s4_wakeup_s2:
55+
SELECT injection_points_detach('exec_insert_before_insert_speculative');
56+
SELECT injection_points_wakeup('exec_insert_before_insert_speculative');
57+
58+
injection_points_detach
59+
-----------------------
60+
61+
(1 row)
62+
63+
injection_points_wakeup
64+
-----------------------
65+
66+
(1 row)
67+
68+
step s4_wakeup_s1:
69+
SELECT injection_points_detach('check_exclusion_or_unique_constraint_no_conflict');
70+
SELECT injection_points_wakeup('check_exclusion_or_unique_constraint_no_conflict');
71+
72+
injection_points_detach
73+
-----------------------
74+
75+
(1 row)
76+
77+
injection_points_wakeup
78+
-----------------------
79+
80+
(1 row)
81+
82+
step s1_start_upsert: <... completed>
83+
step s2_start_upsert: <... completed>
84+
step s3_start_create_index: <... completed>
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
Parsed test spec with 4 sessions
2+
3+
starting permutation: s3_start_create_index s1_start_upsert s4_wakeup_define_index_before_set_valid s2_start_upsert s4_wakeup_s1_from_invalidate_catalog_snapshot s4_wakeup_s2 s4_wakeup_s1
4+
injection_points_attach
5+
-----------------------
6+
7+
(1 row)
8+
9+
injection_points_attach
10+
-----------------------
11+
12+
(1 row)
13+
14+
injection_points_attach
15+
-----------------------
16+
17+
(1 row)
18+
19+
step s3_start_create_index: CREATE UNIQUE INDEX CONCURRENTLY tbl_pkey_special_duplicate ON test.tbl(abs(i)) WHERE i < 10000; <waiting ...>
20+
step s1_start_upsert:
21+
INSERT INTO test.tbl VALUES(13,now()) on conflict(abs(i)) where i < 100 do update set updated_at = now();
22+
<waiting ...>
23+
step s4_wakeup_define_index_before_set_valid:
24+
SELECT injection_points_detach('define_index_before_set_valid');
25+
SELECT injection_points_wakeup('define_index_before_set_valid');
26+
27+
injection_points_detach
28+
-----------------------
29+
30+
(1 row)
31+
32+
injection_points_wakeup
33+
-----------------------
34+
35+
(1 row)
36+
37+
step s2_start_upsert:
38+
INSERT INTO test.tbl VALUES(13,now()) on conflict(abs(i)) where i < 100 do update set updated_at = now();
39+
<waiting ...>
40+
step s4_wakeup_s1_from_invalidate_catalog_snapshot:
41+
SELECT injection_points_detach('invalidate_catalog_snapshot_end');
42+
SELECT injection_points_wakeup('invalidate_catalog_snapshot_end');
43+
44+
injection_points_detach
45+
-----------------------
46+
47+
(1 row)
48+
49+
injection_points_wakeup
50+
-----------------------
51+
52+
(1 row)
53+
54+
step s4_wakeup_s2:
55+
SELECT injection_points_detach('exec_insert_before_insert_speculative');
56+
SELECT injection_points_wakeup('exec_insert_before_insert_speculative');
57+
58+
injection_points_detach
59+
-----------------------
60+
61+
(1 row)
62+
63+
injection_points_wakeup
64+
-----------------------
65+
66+
(1 row)
67+
68+
step s4_wakeup_s1:
69+
SELECT injection_points_detach('check_exclusion_or_unique_constraint_no_conflict');
70+
SELECT injection_points_wakeup('check_exclusion_or_unique_constraint_no_conflict');
71+
72+
injection_points_detach
73+
-----------------------
74+
75+
(1 row)
76+
77+
injection_points_wakeup
78+
-----------------------
79+
80+
(1 row)
81+
82+
step s1_start_upsert: <... completed>
83+
step s2_start_upsert: <... completed>
84+
step s3_start_create_index: <... completed>

0 commit comments

Comments
 (0)