Re: pg_restore causing deadlocks on partitioned tables - Mailing list pgsql-hackers

From Tom Lane
Subject Re: pg_restore causing deadlocks on partitioned tables
Date
Msg-id 1227398.1600128538@sss.pgh.pa.us
Whole thread Raw
In response to Re: pg_restore causing deadlocks on partitioned tables  (Tom Lane <tgl@sss.pgh.pa.us>)
Responses Re: pg_restore causing deadlocks on partitioned tables  (Amit Langote <amitlangote09@gmail.com>)
List pgsql-hackers
I wrote:
>> (2) ALTER TABLE ONLY ... ADD CONSTRAINT on a partition root tries to get
>> AccessExclusiveLock on all child partitions, despite the ONLY.

> The cause of this seems to be that ATPrepSetNotNull is too dumb to
> avoid recursing to all the child tables when the parent is already
> attnotnull.  Or is there a reason we have to recurse anyway?

I wrote a quick patch for this part.  It seems pretty safe and probably
could be back-patched without fear.  (I also noticed that
ATSimpleRecursion is being unnecessarily stupid: instead of the
demonstrably not-future-proof relkind check, it could test relhassubclass,
which is not only simpler and less likely to need future changes, but
is able to save a scan of pg_inherits in a lot more cases.)

As far as I can tell in some quick testing, this fix is sufficient to
resolve the complained-of deadlock.  It'd still be a good idea to fix the
TRUNCATE side of things as well.  But that would be hard to back-patch
because removing ri_PartitionCheck, or even just failing to fill it,
seems like a potential ABI break for extensions.  So my proposal is
to back-patch this, but address the ResultRelInfo change only in HEAD.

            regards, tom lane

diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index c21a309f04..4a51d79d09 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -5681,14 +5681,10 @@ ATSimpleRecursion(List **wqueue, Relation rel,
                   AlterTableUtilityContext *context)
 {
     /*
-     * Propagate to children if desired.  Only plain tables, foreign tables
-     * and partitioned tables have children, so no need to search for other
-     * relkinds.
+     * Propagate to children, if desired and if there are (or might be) any
+     * children.
      */
-    if (recurse &&
-        (rel->rd_rel->relkind == RELKIND_RELATION ||
-         rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE ||
-         rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE))
+    if (recurse && rel->rd_rel->relhassubclass)
     {
         Oid            relid = RelationGetRelid(rel);
         ListCell   *child;
@@ -6698,6 +6694,35 @@ ATPrepSetNotNull(List **wqueue, Relation rel,
     if (recursing)
         return;

+    /*
+     * If the target column is already marked NOT NULL, we can skip recursing
+     * to children, because their columns should already be marked NOT NULL as
+     * well.  But there's no point in checking here unless the relation has
+     * some children; else we can just wait till execution to check.  (If it
+     * does have children, however, this can save taking per-child locks
+     * unnecessarily.  This greatly improves concurrency in some parallel
+     * restore scenarios.)
+     */
+    if (rel->rd_rel->relhassubclass)
+    {
+        HeapTuple    tuple;
+        bool        attnotnull;
+
+        tuple = SearchSysCacheAttName(RelationGetRelid(rel), cmd->name);
+
+        /* Might as well throw the error now, if name is bad */
+        if (!HeapTupleIsValid(tuple))
+            ereport(ERROR,
+                    (errcode(ERRCODE_UNDEFINED_COLUMN),
+                     errmsg("column \"%s\" of relation \"%s\" does not exist",
+                            cmd->name, RelationGetRelationName(rel))));
+
+        attnotnull = ((Form_pg_attribute) GETSTRUCT(tuple))->attnotnull;
+        ReleaseSysCache(tuple);
+        if (attnotnull)
+            return;
+    }
+
     /*
      * If we have ALTER TABLE ONLY ... SET NOT NULL on a partitioned table,
      * apply ALTER TABLE ... CHECK NOT NULL to every child.  Otherwise, use

pgsql-hackers by date:

Previous
From: Soumyadeep Chakraborty
Date:
Subject: Re: Adding Support for Copy callback functionality on COPY TO api
Next
From: Tom Lane
Date:
Subject: Re: Improving connection scalability: GetSnapshotData()