From 3329c6e9807320254ebbd77f526bc6b1b3d623bb Mon Sep 17 00:00:00 2001 From: Vignesh C Date: Tue, 3 Nov 2026 15:40:35 +0530 Subject: [PATCH] Test to reproduce cache lookup failure with vacuum and lock. Test to reproduce cache lookup failure with vacuum and lock. --- src/backend/catalog/pg_inherits.c | 11 +++ src/test/modules/injection_points/Makefile | 1 + .../partition-tree-concurrent-drop.out | 48 ++++++++++++ src/test/modules/injection_points/meson.build | 1 + .../specs/partition-tree-concurrent-drop.spec | 76 +++++++++++++++++++ 5 files changed, 137 insertions(+) create mode 100644 src/test/modules/injection_points/expected/partition-tree-concurrent-drop.out create mode 100644 src/test/modules/injection_points/specs/partition-tree-concurrent-drop.spec diff --git a/src/backend/catalog/pg_inherits.c b/src/backend/catalog/pg_inherits.c index 23fb7886cfb..0554bcc3f0d 100644 --- a/src/backend/catalog/pg_inherits.c +++ b/src/backend/catalog/pg_inherits.c @@ -29,6 +29,7 @@ #include "utils/builtins.h" #include "utils/fmgroids.h" #include "utils/hsearch.h" +#include "utils/injection_point.h" #include "utils/snapmgr.h" #include "utils/syscache.h" @@ -289,6 +290,16 @@ find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents) List *currentchildren; ListCell *lc; +#ifdef USE_INJECTION_POINTS + if (IS_INJECTION_POINT_ATTACHED("find-all-inheritors-before-scan")) + { + char currentrelstr[MAXINT8LEN + 1]; + + snprintf(currentrelstr, sizeof(currentrelstr), "%u", currentrel); + INJECTION_POINT("find-all-inheritors-before-scan", currentrelstr); + } +#endif + /* Get the direct children of this rel */ currentchildren = find_inheritance_children(currentrel, lockmode); diff --git a/src/test/modules/injection_points/Makefile b/src/test/modules/injection_points/Makefile index 8e2dfaa2384..b7ffe0d43f5 100644 --- a/src/test/modules/injection_points/Makefile +++ b/src/test/modules/injection_points/Makefile @@ -36,6 +36,7 @@ ISOLATION = basic \ syscache-update-pruned \ $(WAIT_CLEANUP_TST) \ heap_lock_update \ + partition-tree-concurrent-drop \ on_conflict_probe_window \ multixact-aborted-updater diff --git a/src/test/modules/injection_points/expected/partition-tree-concurrent-drop.out b/src/test/modules/injection_points/expected/partition-tree-concurrent-drop.out new file mode 100644 index 00000000000..b61e2658a8b --- /dev/null +++ b/src/test/modules/injection_points/expected/partition-tree-concurrent-drop.out @@ -0,0 +1,48 @@ +Parsed test spec with 2 sessions + +starting permutation: vacuum_root drop_victim wakeup +injection_points_attach +----------------------- + +(1 row) + +step vacuum_root: VACUUM root; +step drop_victim: DROP TABLE victim; +step wakeup: + SELECT injection_points_wakeup('find-all-inheritors-before-scan'); + +injection_points_wakeup +----------------------- + +(1 row) + +step vacuum_root: <... completed> +injection_points_detach +----------------------- + +(1 row) + + +starting permutation: lock_root drop_victim wakeup commit +injection_points_attach +----------------------- + +(1 row) + +step lock_root: BEGIN; LOCK TABLE root IN ACCESS SHARE MODE; +step drop_victim: DROP TABLE victim; +step wakeup: + SELECT injection_points_wakeup('find-all-inheritors-before-scan'); + +injection_points_wakeup +----------------------- + +(1 row) + +step lock_root: <... completed> +step commit: COMMIT; +injection_points_detach +----------------------- + +(1 row) + diff --git a/src/test/modules/injection_points/meson.build b/src/test/modules/injection_points/meson.build index 97e7a736282..d17559a97e5 100644 --- a/src/test/modules/injection_points/meson.build +++ b/src/test/modules/injection_points/meson.build @@ -43,6 +43,7 @@ injection_points_isolation = [ 'ri_fastpath_snapshot', 'syscache-update-pruned', 'heap_lock_update', + 'partition-tree-concurrent-drop', 'on_conflict_probe_window', 'multixact-aborted-updater', ] diff --git a/src/test/modules/injection_points/specs/partition-tree-concurrent-drop.spec b/src/test/modules/injection_points/specs/partition-tree-concurrent-drop.spec new file mode 100644 index 00000000000..35f93eb273b --- /dev/null +++ b/src/test/modules/injection_points/specs/partition-tree-concurrent-drop.spec @@ -0,0 +1,76 @@ +# Test concurrently dropping a partition while the partition tree of a +# partitioned table is being listed without locking the partitions. +# +# VACUUM and LOCK TABLE list the partitions with find_all_inheritors(NoLock), +# as the callers of that function may do: they do not want to lock the +# partitions yet. Dropping a partition locks only the partition and its direct +# parent, so a partition that is not a direct child of the table can be dropped +# while the list is being built. The command must not fail because of that: +# the partition is just not processed. +# +# root +# |---- p1 +# | +---- trigger +# | +---- leaf +# +---- p2 +# +---- victim +# +# s1 stops in find_all_inheritors() just before it looks for the children of +# "trigger", when "victim" has already been found. s2 drops "victim", which +# does not conflict with s1. When s1 goes on, scanning the children of a +# partitioned table has refreshed its caches, so the lookup of "victim" no +# longer finds it. +# +# The steps are plain commands: they are expected to complete. A failure would +# print "cache lookup failed for relation ". + +setup +{ + CREATE EXTENSION injection_points; + + CREATE TABLE root (a int, b int) PARTITION BY RANGE (a); + CREATE TABLE p1 PARTITION OF root FOR VALUES FROM (0) TO (10) + PARTITION BY RANGE (b); + CREATE TABLE p2 PARTITION OF root FOR VALUES FROM (10) TO (20) + PARTITION BY RANGE (b); + CREATE TABLE trigger PARTITION OF p1 FOR VALUES FROM (0) TO (10) + PARTITION BY HASH (a); + CREATE TABLE leaf PARTITION OF trigger + FOR VALUES WITH (MODULUS 1, REMAINDER 0); + CREATE TABLE victim PARTITION OF p2 FOR VALUES FROM (0) TO (10); +} + +teardown +{ + DROP TABLE root; + DROP EXTENSION injection_points; +} + +session s1 +setup +{ + SELECT injection_points_set_local(); + SELECT injection_points_attach( + 'find-all-inheritors-before-scan', + 'wait', + 'trigger'::regclass::oid::text); +} + +step vacuum_root { VACUUM root; } +step lock_root { BEGIN; LOCK TABLE root IN ACCESS SHARE MODE; } +step commit { COMMIT; } +# The session lives through both permutations, so detach the point. +teardown +{ + SELECT injection_points_detach('find-all-inheritors-before-scan'); +} + +session s2 +step drop_victim { DROP TABLE victim; } +step wakeup +{ + SELECT injection_points_wakeup('find-all-inheritors-before-scan'); +} + +permutation vacuum_root drop_victim wakeup +permutation lock_root drop_victim wakeup commit -- 2.55.0