On Thu, Apr 14, 2022 at 10:37:06PM +0200, Alvaro Herrera wrote:
> Thanks for the patch -- I have pushed it now, with some wording changes
> and renaming the role to regress_* to avoid buildfarm's ire.

Cool, thanks.

> Michaƫl in addition proposes an isolation test.  I'm not sure; is it
> worth the additional test run time?  It doesn't seem a critical issue.
> But if anybody feels like contributing one, step right ahead.

Well, I am a bit annoyed that we don't actually check that a CLUSTER
command does not block when doing a CLUSTER on a partitioned table
while a lock is held on one of its partitions.  So, attached is a
proposal of patch to improve the test coverage in this area.  While on
it, I have added a test with a normal table.  You can see the
difference once you remove the ACL check added recently in
get_tables_to_cluster_partitioned().  What do you think?
--
Michael
From fdf5347bf4853f19341a8d67a655cae9fece15f0 Mon Sep 17 00:00:00 2001
From: Michael Paquier <mich...@paquier.xyz>
Date: Sat, 16 Apr 2022 20:52:03 +0900
Subject: [PATCH] Add isolation tests for CLUSTER with partitions

---
 .../expected/cluster-conflict-partition.out   | 35 ++++++++++++++++++
 .../isolation/expected/cluster-conflict.out   | 19 ++++++++++
 src/test/isolation/isolation_schedule         |  2 +
 .../specs/cluster-conflict-partition.spec     | 37 +++++++++++++++++++
 .../isolation/specs/cluster-conflict.spec     | 30 +++++++++++++++
 5 files changed, 123 insertions(+)
 create mode 100644 src/test/isolation/expected/cluster-conflict-partition.out
 create mode 100644 src/test/isolation/expected/cluster-conflict.out
 create mode 100644 src/test/isolation/specs/cluster-conflict-partition.spec
 create mode 100644 src/test/isolation/specs/cluster-conflict.spec

diff --git a/src/test/isolation/expected/cluster-conflict-partition.out b/src/test/isolation/expected/cluster-conflict-partition.out
new file mode 100644
index 0000000000..7acb675c97
--- /dev/null
+++ b/src/test/isolation/expected/cluster-conflict-partition.out
@@ -0,0 +1,35 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1_begin s1_lock_parent s2_auth s2_cluster s1_commit s2_reset
+step s1_begin: BEGIN;
+step s1_lock_parent: LOCK cluster_part_tab IN SHARE UPDATE EXCLUSIVE MODE;
+step s2_auth: SET ROLE regress_cluster_part;
+step s2_cluster: CLUSTER cluster_part_tab USING cluster_part_ind; <waiting ...>
+step s1_commit: COMMIT;
+step s2_cluster: <... completed>
+step s2_reset: RESET ROLE;
+
+starting permutation: s1_begin s2_auth s1_lock_parent s2_cluster s1_commit s2_reset
+step s1_begin: BEGIN;
+step s2_auth: SET ROLE regress_cluster_part;
+step s1_lock_parent: LOCK cluster_part_tab IN SHARE UPDATE EXCLUSIVE MODE;
+step s2_cluster: CLUSTER cluster_part_tab USING cluster_part_ind; <waiting ...>
+step s1_commit: COMMIT;
+step s2_cluster: <... completed>
+step s2_reset: RESET ROLE;
+
+starting permutation: s1_begin s1_lock_child s2_auth s2_cluster s1_commit s2_reset
+step s1_begin: BEGIN;
+step s1_lock_child: LOCK cluster_part_tab1 IN SHARE UPDATE EXCLUSIVE MODE;
+step s2_auth: SET ROLE regress_cluster_part;
+step s2_cluster: CLUSTER cluster_part_tab USING cluster_part_ind;
+step s1_commit: COMMIT;
+step s2_reset: RESET ROLE;
+
+starting permutation: s1_begin s2_auth s1_lock_child s2_cluster s1_commit s2_reset
+step s1_begin: BEGIN;
+step s2_auth: SET ROLE regress_cluster_part;
+step s1_lock_child: LOCK cluster_part_tab1 IN SHARE UPDATE EXCLUSIVE MODE;
+step s2_cluster: CLUSTER cluster_part_tab USING cluster_part_ind;
+step s1_commit: COMMIT;
+step s2_reset: RESET ROLE;
diff --git a/src/test/isolation/expected/cluster-conflict.out b/src/test/isolation/expected/cluster-conflict.out
new file mode 100644
index 0000000000..614d8f9d15
--- /dev/null
+++ b/src/test/isolation/expected/cluster-conflict.out
@@ -0,0 +1,19 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s1_begin s1_lock s2_auth s2_cluster s1_commit s2_reset
+step s1_begin: BEGIN;
+step s1_lock: LOCK cluster_tab IN SHARE UPDATE EXCLUSIVE MODE;
+step s2_auth: SET ROLE regress_cluster_conflict;
+step s2_cluster: CLUSTER cluster_tab USING cluster_ind; <waiting ...>
+step s1_commit: COMMIT;
+step s2_cluster: <... completed>
+step s2_reset: RESET ROLE;
+
+starting permutation: s1_begin s2_auth s1_lock s2_cluster s1_commit s2_reset
+step s1_begin: BEGIN;
+step s2_auth: SET ROLE regress_cluster_conflict;
+step s1_lock: LOCK cluster_tab IN SHARE UPDATE EXCLUSIVE MODE;
+step s2_cluster: CLUSTER cluster_tab USING cluster_ind; <waiting ...>
+step s1_commit: COMMIT;
+step s2_cluster: <... completed>
+step s2_reset: RESET ROLE;
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 607760386e..529a4cbd4d 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -102,6 +102,8 @@ test: partition-key-update-2
 test: partition-key-update-3
 test: partition-key-update-4
 test: plpgsql-toast
+test: cluster-conflict
+test: cluster-conflict-partition
 test: truncate-conflict
 test: serializable-parallel
 test: serializable-parallel-2
diff --git a/src/test/isolation/specs/cluster-conflict-partition.spec b/src/test/isolation/specs/cluster-conflict-partition.spec
new file mode 100644
index 0000000000..5091f684a9
--- /dev/null
+++ b/src/test/isolation/specs/cluster-conflict-partition.spec
@@ -0,0 +1,37 @@
+# Tests for locking conflicts with CLUSTER command and partitions.
+
+setup
+{
+	CREATE ROLE regress_cluster_part;
+	CREATE TABLE cluster_part_tab (a int) PARTITION BY LIST (a);
+	CREATE TABLE cluster_part_tab1 PARTITION OF cluster_part_tab FOR VALUES IN (1);
+	CREATE TABLE cluster_part_tab2 PARTITION OF cluster_part_tab FOR VALUES IN (2);
+	CREATE INDEX cluster_part_ind ON cluster_part_tab(a);
+	ALTER TABLE cluster_part_tab OWNER TO regress_cluster_part;
+}
+
+teardown
+{
+	DROP TABLE cluster_part_tab;
+	DROP ROLE regress_cluster_part;
+}
+
+session s1
+step s1_begin          { BEGIN; }
+step s1_lock_parent    { LOCK cluster_part_tab IN SHARE UPDATE EXCLUSIVE MODE; }
+step s1_lock_child     { LOCK cluster_part_tab1 IN SHARE UPDATE EXCLUSIVE MODE; }
+step s1_commit         { COMMIT; }
+
+session s2
+step s2_auth           { SET ROLE regress_cluster_part; }
+step s2_cluster        { CLUSTER cluster_part_tab USING cluster_part_ind; }
+step s2_reset          { RESET ROLE; }
+
+# CLUSTER on the parent waits if locked, passes for all cases.
+permutation s1_begin s1_lock_parent s2_auth s2_cluster s1_commit s2_reset
+permutation s1_begin s2_auth s1_lock_parent s2_cluster s1_commit s2_reset
+
+# When taking a lock on a partition leaf, CLUSTER on the parent skips
+# the leaf, passes for all cases.
+permutation s1_begin s1_lock_child s2_auth s2_cluster s1_commit s2_reset
+permutation s1_begin s2_auth s1_lock_child s2_cluster s1_commit s2_reset
diff --git a/src/test/isolation/specs/cluster-conflict.spec b/src/test/isolation/specs/cluster-conflict.spec
new file mode 100644
index 0000000000..2e1d547f01
--- /dev/null
+++ b/src/test/isolation/specs/cluster-conflict.spec
@@ -0,0 +1,30 @@
+# Tests for locking conflicts with CLUSTER command.
+
+setup
+{
+	CREATE ROLE regress_cluster_conflict;
+	CREATE TABLE cluster_tab (a int);
+	CREATE INDEX cluster_ind ON cluster_tab(a);
+	ALTER TABLE cluster_tab OWNER TO regress_cluster_conflict;
+}
+
+teardown
+{
+	DROP TABLE cluster_tab;
+	DROP ROLE regress_cluster_conflict;
+}
+
+session s1
+step s1_begin          { BEGIN; }
+step s1_lock           { LOCK cluster_tab IN SHARE UPDATE EXCLUSIVE MODE; }
+step s1_commit         { COMMIT; }
+
+session s2
+step s2_auth           { SET ROLE regress_cluster_conflict; }
+step s2_cluster        { CLUSTER cluster_tab USING cluster_ind; }
+step s2_reset          { RESET ROLE; }
+
+# The role has privileges to cluster the table, CLUSTER will block if
+# another session holds a lock on the table and succeed in all cases.
+permutation s1_begin s1_lock s2_auth s2_cluster s1_commit s2_reset
+permutation s1_begin s2_auth s1_lock s2_cluster s1_commit s2_reset
-- 
2.35.2

Attachment: signature.asc
Description: PGP signature

Reply via email to