From a970360bc97f5d59b4d6919700432ae7d2573c73 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Thu, 5 Apr 2018 16:52:56 +0000
Subject: [PATCH v7 02/12] Add skip_locked argument to find_all_inheritors().

---
 contrib/sepgsql/dml.c                  |  2 +-
 src/backend/catalog/partition.c        |  2 +-
 src/backend/catalog/pg_inherits.c      | 30 +++++++++++++++++++++++++++---
 src/backend/commands/analyze.c         |  2 +-
 src/backend/commands/publicationcmds.c |  2 +-
 src/backend/commands/tablecmds.c       | 18 +++++++++---------
 src/backend/commands/trigger.c         |  2 +-
 src/backend/commands/vacuum.c          |  2 +-
 src/backend/executor/execPartition.c   |  2 +-
 src/backend/optimizer/prep/prepunion.c |  2 +-
 src/backend/tcop/utility.c             |  2 +-
 src/include/catalog/pg_inherits_fn.h   |  2 +-
 12 files changed, 46 insertions(+), 22 deletions(-)

diff --git a/contrib/sepgsql/dml.c b/contrib/sepgsql/dml.c
index c1fa320eb4..bbc72a59a2 100644
--- a/contrib/sepgsql/dml.c
+++ b/contrib/sepgsql/dml.c
@@ -330,7 +330,7 @@ sepgsql_dml_privileges(List *rangeTabls, bool abort_on_violation)
 		if (!rte->inh)
 			tableIds = list_make1_oid(rte->relid);
 		else
-			tableIds = find_all_inheritors(rte->relid, NoLock, NULL);
+			tableIds = find_all_inheritors(rte->relid, NoLock, NULL, false);
 
 		foreach(li, tableIds)
 		{
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 42453c5007..b701073dcb 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -1270,7 +1270,7 @@ check_default_allows_bound(Relation parent, Relation default_rel,
 	 */
 	if (default_rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
 		all_parts = find_all_inheritors(RelationGetRelid(default_rel),
-										AccessExclusiveLock, NULL);
+										AccessExclusiveLock, NULL, false);
 	else
 		all_parts = list_make1_oid(RelationGetRelid(default_rel));
 
diff --git a/src/backend/catalog/pg_inherits.c b/src/backend/catalog/pg_inherits.c
index 17f8b58fba..c986540974 100644
--- a/src/backend/catalog/pg_inherits.c
+++ b/src/backend/catalog/pg_inherits.c
@@ -181,10 +181,12 @@ find_inheritance_children(Oid parentrelId, LOCKMODE lockmode, bool skip_locked,
  * The specified lock type is acquired on all child relations (but not on the
  * given rel; caller should already have locked it).  If lockmode is NoLock
  * then no locks are acquired, but caller must beware of race conditions
- * against possible DROPs of child relations.
+ * against possible DROPs of child relations.  If skip_locked is true and a
+ * child relation can not be locked immediately without waiting, both the
+ * returned OID list and *numparents will be set to NIL.
  */
 List *
-find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
+find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents, bool skip_locked)
 {
 	/* hash table for O(1) rel_oid -> rel_numparents cell lookup */
 	HTAB	   *seen_rels;
@@ -192,6 +194,7 @@ find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
 	List	   *rels_list,
 			   *rel_numparents;
 	ListCell   *l;
+	bool		skipped = false;
 
 	memset(&ctl, 0, sizeof(ctl));
 	ctl.keysize = sizeof(Oid);
@@ -220,7 +223,7 @@ find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
 		ListCell   *lc;
 
 		/* Get the direct children of this rel */
-		currentchildren = find_inheritance_children(currentrel, lockmode, false, NULL);
+		currentchildren = find_inheritance_children(currentrel, lockmode, skip_locked, &skipped);
 
 		/*
 		 * Add to the queue only those children not already seen. This avoids
@@ -249,6 +252,27 @@ find_all_inheritors(Oid parentrelId, LOCKMODE lockmode, List **numparents)
 				hash_entry->numparents_cell = rel_numparents->tail;
 			}
 		}
+
+		if (skipped)
+			break;
+	}
+
+	/* if a child relation was skipped, set the return lists to NIL */
+	if (skipped)
+	{
+		/* release all locks */
+		foreach(l, rels_list)
+		{
+			Oid			currentrel = lfirst_oid(l);
+
+			if (currentrel != parentrelId)
+				UnlockRelationOid(currentrel, lockmode);
+		}
+
+		list_free(rel_numparents);
+		list_free(rels_list);
+		rel_numparents = NIL;
+		rels_list = NIL;
 	}
 
 	if (numparents)
diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 378784a93c..451e923132 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -1335,7 +1335,7 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
 	 * the children.
 	 */
 	tableOIDs =
-		find_all_inheritors(RelationGetRelid(onerel), AccessShareLock, NULL);
+		find_all_inheritors(RelationGetRelid(onerel), AccessShareLock, NULL, false);
 
 	/*
 	 * Check that there's at least one descendant, else fail.  This could
diff --git a/src/backend/commands/publicationcmds.c b/src/backend/commands/publicationcmds.c
index 9c5aa9ebc2..b347d671a5 100644
--- a/src/backend/commands/publicationcmds.c
+++ b/src/backend/commands/publicationcmds.c
@@ -516,7 +516,7 @@ OpenTableList(List *tables)
 			List	   *children;
 
 			children = find_all_inheritors(myrelid, ShareUpdateExclusiveLock,
-										   NULL);
+										   NULL, false);
 
 			foreach(child, children)
 			{
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 15017c5a62..3d19dd728f 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -1356,7 +1356,7 @@ ExecuteTruncate(TruncateStmt *stmt)
 			ListCell   *child;
 			List	   *children;
 
-			children = find_all_inheritors(myrelid, AccessExclusiveLock, NULL);
+			children = find_all_inheritors(myrelid, AccessExclusiveLock, NULL, false);
 
 			foreach(child, children)
 			{
@@ -2667,7 +2667,7 @@ renameatt_internal(Oid myrelid,
 		 * outside the inheritance hierarchy being processed.
 		 */
 		child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
-										 &child_numparents);
+										 &child_numparents, false);
 
 		/*
 		 * find_all_inheritors does the recursive search of the inheritance
@@ -2877,7 +2877,7 @@ rename_constraint_internal(Oid myrelid,
 					   *li;
 
 			child_oids = find_all_inheritors(myrelid, AccessExclusiveLock,
-											 &child_numparents);
+											 &child_numparents, false);
 
 			forboth(lo, child_oids, li, child_numparents)
 			{
@@ -4943,7 +4943,7 @@ ATSimpleRecursion(List **wqueue, Relation rel,
 		ListCell   *child;
 		List	   *children;
 
-		children = find_all_inheritors(relid, lockmode, NULL);
+		children = find_all_inheritors(relid, lockmode, NULL, false);
 
 		/*
 		 * find_all_inheritors does the recursive search of the inheritance
@@ -7918,7 +7918,7 @@ ATExecValidateConstraint(Relation rel, char *constrName, bool recurse,
 			 */
 			if (!recursing && !con->connoinherit)
 				children = find_all_inheritors(RelationGetRelid(rel),
-											   lockmode, NULL);
+											   lockmode, NULL, false);
 
 			/*
 			 * For CHECK constraints, we must ensure that we only mark the
@@ -9122,7 +9122,7 @@ ATPrepAlterColumnType(List **wqueue,
 		ListCell   *child;
 		List	   *children;
 
-		children = find_all_inheritors(relid, lockmode, NULL);
+		children = find_all_inheritors(relid, lockmode, NULL, false);
 
 		/*
 		 * find_all_inheritors does the recursive search of the inheritance
@@ -11355,7 +11355,7 @@ ATExecAddInherit(Relation child_rel, RangeVar *parent, LOCKMODE lockmode)
 	 * We use weakest lock we can on child's children, namely AccessShareLock.
 	 */
 	children = find_all_inheritors(RelationGetRelid(child_rel),
-								   AccessShareLock, NULL);
+								   AccessShareLock, NULL, false);
 
 	if (list_member_oid(children, RelationGetRelid(parent_rel)))
 		ereport(ERROR,
@@ -14059,7 +14059,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
 	 * weaker lock now and the stronger one only when needed.
 	 */
 	attachrel_children = find_all_inheritors(RelationGetRelid(attachrel),
-											 AccessExclusiveLock, NULL);
+											 AccessExclusiveLock, NULL, false);
 	if (list_member_oid(attachrel_children, RelationGetRelid(rel)))
 		ereport(ERROR,
 				(errcode(ERRCODE_DUPLICATE_TABLE),
@@ -14252,7 +14252,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
 			get_proposed_default_constraint(partBoundConstraint);
 		defaultrel_children =
 			find_all_inheritors(defaultPartOid,
-								AccessExclusiveLock, NULL);
+								AccessExclusiveLock, NULL, false);
 		ValidatePartitionConstraints(wqueue, defaultrel,
 									 defaultrel_children,
 									 defPartConstraint, true);
diff --git a/src/backend/commands/trigger.c b/src/backend/commands/trigger.c
index a7e549e0ae..1aa65ffc97 100644
--- a/src/backend/commands/trigger.c
+++ b/src/backend/commands/trigger.c
@@ -371,7 +371,7 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
 		rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE;
 	if (partition_recurse)
 		list_free(find_all_inheritors(RelationGetRelid(rel),
-									  ShareRowExclusiveLock, NULL));
+									  ShareRowExclusiveLock, NULL, false));
 
 	/* Compute tgtype */
 	TRIGGER_CLEAR_TYPE(tgtype);
diff --git a/src/backend/commands/vacuum.c b/src/backend/commands/vacuum.c
index a1782c2874..db1b6e2d26 100644
--- a/src/backend/commands/vacuum.c
+++ b/src/backend/commands/vacuum.c
@@ -479,7 +479,7 @@ expand_vacuum_rel(VacuumRelation *vrel)
 		 */
 		if (include_parts)
 		{
-			List	   *part_oids = find_all_inheritors(relid, NoLock, NULL);
+			List	   *part_oids = find_all_inheritors(relid, NoLock, NULL, false);
 			ListCell   *part_lc;
 
 			foreach(part_lc, part_oids)
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index ad532773a3..bf77eedbcb 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -77,7 +77,7 @@ ExecSetupPartitionTupleRouting(ModifyTableState *mtstate, Relation rel)
 	 * Get the information about the partition tree after locking all the
 	 * partitions.
 	 */
-	(void) find_all_inheritors(RelationGetRelid(rel), RowExclusiveLock, NULL);
+	(void) find_all_inheritors(RelationGetRelid(rel), RowExclusiveLock, NULL, false);
 	proute = (PartitionTupleRouting *) palloc0(sizeof(PartitionTupleRouting));
 	proute->partition_dispatch_info =
 		RelationGetPartitionDispatchInfo(rel, &proute->num_dispatch,
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index 5236ab378e..d5112a6ec8 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -1556,7 +1556,7 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
 		lockmode = AccessShareLock;
 
 	/* Scan for all members of inheritance set, acquire needed locks */
-	inhOIDs = find_all_inheritors(parentOID, lockmode, NULL);
+	inhOIDs = find_all_inheritors(parentOID, lockmode, NULL, false);
 
 	/*
 	 * Check that there's at least one descendant, else treat as no-child
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
index 84f2591736..af4e1fb0ff 100644
--- a/src/backend/tcop/utility.c
+++ b/src/backend/tcop/utility.c
@@ -1323,7 +1323,7 @@ ProcessUtilitySlow(ParseState *pstate,
 						rel = heap_open(relid, NoLock);
 						if (rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
 							inheritors = find_all_inheritors(relid, lockmode,
-															 NULL);
+															 NULL, false);
 						heap_close(rel, NoLock);
 					}
 
diff --git a/src/include/catalog/pg_inherits_fn.h b/src/include/catalog/pg_inherits_fn.h
index 34d2a2f39f..5374dc48da 100644
--- a/src/include/catalog/pg_inherits_fn.h
+++ b/src/include/catalog/pg_inherits_fn.h
@@ -20,7 +20,7 @@
 extern List *find_inheritance_children(Oid parentrelId, LOCKMODE lockmode,
 						  bool skip_locked, bool *skipped);
 extern List *find_all_inheritors(Oid parentrelId, LOCKMODE lockmode,
-					List **parents);
+					List **parents, bool skip_locked);
 extern bool has_subclass(Oid relationId);
 extern bool has_superclass(Oid relationId);
 extern bool typeInheritsFrom(Oid subclassTypeId, Oid superclassTypeId);
-- 
2.16.2

