v1-0001-spec-to-reproduce-issue-with-REINDEX-CONCURRENTLY.patch
text/x-patch
Filename: v1-0001-spec-to-reproduce-issue-with-REINDEX-CONCURRENTLY.patch
Type: text/x-patch
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: format-patch
Series: patch v1-0001
Subject: spec to reproduce issue with REINDEX CONCURRENTLY and INSERT ON CONFLICT UPDATE
| File | + | − |
|---|---|---|
| src/backend/commands/indexcmds.c | 2 | 1 |
| src/backend/executor/execIndexing.c | 3 | 0 |
| src/backend/executor/nodeModifyTable.c | 3 | 0 |
| src/test/modules/injection_points/expected/reindex_concurrently_upsert.out | 131 | 0 |
| src/test/modules/injection_points/Makefile | 1 | 1 |
| src/test/modules/injection_points/meson.build | 1 | 0 |
| src/test/modules/injection_points/specs/reindex_concurrently_upsert.spec | 70 | 0 |
From 6731d0a2df03eb291b05b5424f8e4aa63c2216ee Mon Sep 17 00:00:00 2001
From: nkey <nkey@toloka.ai>
Date: Sun, 4 Aug 2024 21:24:49 +0200
Subject: [PATCH v1] spec to reproduce issue with REINDEX CONCURRENTLY and
INSERT ON CONFLICT UPDATE
---
src/backend/commands/indexcmds.c | 3 +-
src/backend/executor/execIndexing.c | 3 +
src/backend/executor/nodeModifyTable.c | 3 +
src/test/modules/injection_points/Makefile | 2 +-
.../expected/reindex_concurrently_upsert.out | 131 ++++++++++++++++++
src/test/modules/injection_points/meson.build | 1 +
.../specs/reindex_concurrently_upsert.spec | 70 ++++++++++
7 files changed, 211 insertions(+), 2 deletions(-)
create mode 100644 src/test/modules/injection_points/expected/reindex_concurrently_upsert.out
create mode 100644 src/test/modules/injection_points/specs/reindex_concurrently_upsert.spec
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 2caab88aa5..9437654b11 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -69,6 +69,7 @@
#include "utils/regproc.h"
#include "utils/snapmgr.h"
#include "utils/syscache.h"
+#include "utils/injection_point.h"
/* non-export function prototypes */
@@ -4078,7 +4079,7 @@ ReindexRelationConcurrently(const ReindexStmt *stmt, Oid relationOid, const Rein
* the same time to make sure we only get constraint violations from the
* indexes with the correct names.
*/
-
+ INJECTION_POINT("reindex_relation_concurrently_before_swap");
StartTransactionCommand();
/*
diff --git a/src/backend/executor/execIndexing.c b/src/backend/executor/execIndexing.c
index 9f05b3654c..1d451a329a 100644
--- a/src/backend/executor/execIndexing.c
+++ b/src/backend/executor/execIndexing.c
@@ -115,6 +115,7 @@
#include "nodes/nodeFuncs.h"
#include "storage/lmgr.h"
#include "utils/snapmgr.h"
+#include "utils/injection_point.h"
/* waitMode argument to check_exclusion_or_unique_constraint() */
typedef enum
@@ -901,6 +902,8 @@ retry:
econtext->ecxt_scantuple = save_scantuple;
ExecDropSingleTupleTableSlot(existing_slot);
+ if (!conflict)
+ INJECTION_POINT("check_exclusion_or_unique_constraint_no_conflict");
return !conflict;
}
diff --git a/src/backend/executor/nodeModifyTable.c b/src/backend/executor/nodeModifyTable.c
index 4913e49319..d91b0a1cc7 100644
--- a/src/backend/executor/nodeModifyTable.c
+++ b/src/backend/executor/nodeModifyTable.c
@@ -69,6 +69,7 @@
#include "utils/datum.h"
#include "utils/rel.h"
#include "utils/snapmgr.h"
+#include "utils/injection_point.h"
typedef struct MTTargetRelLookup
@@ -1085,6 +1086,8 @@ ExecInsert(ModifyTableContext *context,
}
}
+ INJECTION_POINT("exec_insert_before_insert_speculative");
+
/*
* Before we start insertion proper, acquire our "speculative
* insertion lock". Others can use that to wait for us to decide
diff --git a/src/test/modules/injection_points/Makefile b/src/test/modules/injection_points/Makefile
index 2ffd2f77ed..f8a2a7630d 100644
--- a/src/test/modules/injection_points/Makefile
+++ b/src/test/modules/injection_points/Makefile
@@ -9,7 +9,7 @@ PGFILEDESC = "injection_points - facility for injection points"
REGRESS = injection_points
REGRESS_OPTS = --dlpath=$(top_builddir)/src/test/regress
-ISOLATION = inplace
+ISOLATION = inplace reindex_concurrently_upsert
# The injection points are cluster-wide, so disable installcheck
NO_INSTALLCHECK = 1
diff --git a/src/test/modules/injection_points/expected/reindex_concurrently_upsert.out b/src/test/modules/injection_points/expected/reindex_concurrently_upsert.out
new file mode 100644
index 0000000000..3e855e2223
--- /dev/null
+++ b/src/test/modules/injection_points/expected/reindex_concurrently_upsert.out
@@ -0,0 +1,131 @@
+Parsed test spec with 4 sessions
+
+starting permutation: s3_s1 s1_s1 s4_s1 s2_s1 s4_s2 s4_s3
+injection_points_attach
+-----------------------
+
+(1 row)
+
+injection_points_attach
+-----------------------
+
+(1 row)
+
+injection_points_attach
+-----------------------
+
+(1 row)
+
+step s3_s1: REINDEX INDEX CONCURRENTLY test.tbl_pkey; <waiting ...>
+step s1_s1: INSERT INTO test.tbl VALUES(13,now()) on conflict(i) do update set updated_at = now(); <waiting ...>
+step s4_s1:
+ SELECT injection_points_wakeup('reindex_relation_concurrently_before_swap');
+ SELECT injection_points_detach('reindex_relation_concurrently_before_swap');
+
+injection_points_wakeup
+-----------------------
+
+(1 row)
+
+injection_points_detach
+-----------------------
+
+(1 row)
+
+step s2_s1: INSERT INTO test.tbl VALUES(13,now()) on conflict(i) do update set updated_at = now(); <waiting ...>
+step s4_s2:
+ SELECT injection_points_wakeup('check_exclusion_or_unique_constraint_no_conflict');
+ SELECT injection_points_detach('check_exclusion_or_unique_constraint_no_conflict');
+
+injection_points_wakeup
+-----------------------
+
+(1 row)
+
+injection_points_detach
+-----------------------
+
+(1 row)
+
+step s1_s1: <... completed>
+step s4_s3:
+ SELECT injection_points_wakeup('exec_insert_before_insert_speculative');
+ SELECT injection_points_detach('exec_insert_before_insert_speculative');
+
+injection_points_wakeup
+-----------------------
+
+(1 row)
+
+injection_points_detach
+-----------------------
+
+(1 row)
+
+step s3_s1: <... completed>
+step s2_s1: <... completed>
+
+starting permutation: s3_s1 s2_s1 s4_s1 s1_s1 s4_s2 s4_s3
+injection_points_attach
+-----------------------
+
+(1 row)
+
+injection_points_attach
+-----------------------
+
+(1 row)
+
+injection_points_attach
+-----------------------
+
+(1 row)
+
+step s3_s1: REINDEX INDEX CONCURRENTLY test.tbl_pkey; <waiting ...>
+step s2_s1: INSERT INTO test.tbl VALUES(13,now()) on conflict(i) do update set updated_at = now(); <waiting ...>
+step s4_s1:
+ SELECT injection_points_wakeup('reindex_relation_concurrently_before_swap');
+ SELECT injection_points_detach('reindex_relation_concurrently_before_swap');
+
+injection_points_wakeup
+-----------------------
+
+(1 row)
+
+injection_points_detach
+-----------------------
+
+(1 row)
+
+step s1_s1: INSERT INTO test.tbl VALUES(13,now()) on conflict(i) do update set updated_at = now(); <waiting ...>
+step s4_s2:
+ SELECT injection_points_wakeup('check_exclusion_or_unique_constraint_no_conflict');
+ SELECT injection_points_detach('check_exclusion_or_unique_constraint_no_conflict');
+
+injection_points_wakeup
+-----------------------
+
+(1 row)
+
+injection_points_detach
+-----------------------
+
+(1 row)
+
+step s1_s1: <... completed>
+step s4_s3:
+ SELECT injection_points_wakeup('exec_insert_before_insert_speculative');
+ SELECT injection_points_detach('exec_insert_before_insert_speculative');
+
+injection_points_wakeup
+-----------------------
+
+(1 row)
+
+injection_points_detach
+-----------------------
+
+(1 row)
+
+step s3_s1: <... completed>
+step s2_s1: <... completed>
diff --git a/src/test/modules/injection_points/meson.build b/src/test/modules/injection_points/meson.build
index 3c23c14d81..7caa9769b2 100644
--- a/src/test/modules/injection_points/meson.build
+++ b/src/test/modules/injection_points/meson.build
@@ -40,6 +40,7 @@ tests += {
'isolation': {
'specs': [
'inplace',
+ 'reindex_concurrently_upsert',
],
},
}
diff --git a/src/test/modules/injection_points/specs/reindex_concurrently_upsert.spec b/src/test/modules/injection_points/specs/reindex_concurrently_upsert.spec
new file mode 100644
index 0000000000..fcaee1a21c
--- /dev/null
+++ b/src/test/modules/injection_points/specs/reindex_concurrently_upsert.spec
@@ -0,0 +1,70 @@
+# Test race conditions involving:
+# - s1: UPSERT a tuple
+# - s2: UPSERT the same tuple
+# - s3: REINDEX concurrent primary key index
+# - 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_s1 { 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_s1 { 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('reindex_relation_concurrently_before_swap', 'wait');
+}
+step s3_s1 { REINDEX INDEX CONCURRENTLY test.tbl_pkey; }
+
+session s4
+step s4_s1 {
+ SELECT injection_points_wakeup('reindex_relation_concurrently_before_swap');
+ SELECT injection_points_detach('reindex_relation_concurrently_before_swap');
+}
+step s4_s2 {
+ SELECT injection_points_wakeup('check_exclusion_or_unique_constraint_no_conflict');
+ SELECT injection_points_detach('check_exclusion_or_unique_constraint_no_conflict');
+}
+step s4_s3 {
+ SELECT injection_points_wakeup('exec_insert_before_insert_speculative');
+ SELECT injection_points_detach('exec_insert_before_insert_speculative');
+}
+
+permutation
+ s3_s1
+ s1_s1
+ s4_s1
+ s2_s1
+ s4_s2
+ s4_s3
+
+permutation
+ s3_s1
+ s2_s1
+ s4_s1
+ s1_s1
+ s4_s2
+ s4_s3
\ No newline at end of file
--
2.34.1