From c181744cdf9c7970209013787b6e62fb5de5dac7 Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Wed, 5 Sep 2018 14:44:15 +0000
Subject: [PATCH v9 5/7] Skip ANALYZE with VACOPT_SKIP_LOCKED if
 acquire_inherited_sample_rows() blocks.

---
 src/backend/commands/analyze.c | 62 ++++++++++++++++++++++++++++++++++--------
 1 file changed, 51 insertions(+), 11 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 26fa7bcd55..bc215e7c00 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -84,7 +84,7 @@ static BufferAccessStrategy vac_strategy;
 static void do_analyze_rel(Relation onerel, int options,
 			   VacuumParams *params, List *va_cols,
 			   AcquireSampleRowsFunc acquirefunc, BlockNumber relpages,
-			   bool inh, bool in_outer_xact, int elevel);
+			   bool inh, bool in_outer_xact, int elevel, RangeVar *rangeVar);
 static void compute_index_stats(Relation onerel, double totalrows,
 					AnlIndexData *indexdata, int nindexes,
 					HeapTuple *rows, int numrows,
@@ -97,7 +97,8 @@ static int acquire_sample_rows(Relation onerel, int elevel,
 static int	compare_rows(const void *a, const void *b);
 static int acquire_inherited_sample_rows(Relation onerel, int elevel,
 							  HeapTuple *rows, int targrows,
-							  double *totalrows, double *totaldeadrows);
+							  double *totalrows, double *totaldeadrows,
+							  bool skip_locked, bool *skipped);
 static void update_attstats(Oid relid, bool inh,
 				int natts, VacAttrStats **vacattrstats);
 static Datum std_fetch_func(VacAttrStatsP stats, int rownum, bool *isNull);
@@ -284,14 +285,14 @@ analyze_rel(Oid relid, RangeVar *relation, int options,
 	 */
 	if (onerel->rd_rel->relkind != RELKIND_PARTITIONED_TABLE)
 		do_analyze_rel(onerel, options, params, va_cols, acquirefunc,
-					   relpages, false, in_outer_xact, elevel);
+					   relpages, false, in_outer_xact, elevel, relation);
 
 	/*
 	 * If there are child tables, do recursive ANALYZE.
 	 */
 	if (onerel->rd_rel->relhassubclass)
 		do_analyze_rel(onerel, options, params, va_cols, acquirefunc, relpages,
-					   true, in_outer_xact, elevel);
+					   true, in_outer_xact, elevel, relation);
 
 	/*
 	 * Close source relation now, but keep lock so that no one deletes it
@@ -321,7 +322,7 @@ static void
 do_analyze_rel(Relation onerel, int options, VacuumParams *params,
 			   List *va_cols, AcquireSampleRowsFunc acquirefunc,
 			   BlockNumber relpages, bool inh, bool in_outer_xact,
-			   int elevel)
+			   int elevel, RangeVar *rangeVar)
 {
 	int			attr_cnt,
 				tcnt,
@@ -343,6 +344,7 @@ do_analyze_rel(Relation onerel, int options, VacuumParams *params,
 	Oid			save_userid;
 	int			save_sec_context;
 	int			save_nestlevel;
+	bool		skipped = false;
 
 	if (inh)
 		ereport(elevel,
@@ -521,9 +523,23 @@ do_analyze_rel(Relation onerel, int options, VacuumParams *params,
 	 */
 	rows = (HeapTuple *) palloc(targrows * sizeof(HeapTuple));
 	if (inh)
+	{
 		numrows = acquire_inherited_sample_rows(onerel, elevel,
 												rows, targrows,
-												&totalrows, &totaldeadrows);
+												&totalrows, &totaldeadrows,
+												(options & VACOPT_SKIP_LOCKED), &skipped);
+
+		/*
+		 * If SKIP LOCKED is specified and we would have to wait for a lock on
+		 * a child relation, skip analyzing the relation.
+		 */
+		if (skipped)
+		{
+			do_analyze_rel_cleanup(save_nestlevel, save_userid, save_sec_context,
+								   caller_context, rangeVar, params);
+			return;
+		}
+	}
 	else
 		numrows = (*acquirefunc) (onerel, elevel,
 								  rows, targrows,
@@ -1308,15 +1324,20 @@ compare_rows(const void *a, const void *b)
 /*
  * acquire_inherited_sample_rows -- acquire sample rows from inheritance tree
  *
- * This has the same API as acquire_sample_rows, except that rows are
+ * This has roughly the same API as acquire_sample_rows, except that rows are
  * collected from all inheritance children as well as the specified table.
- * We fail and return zero if there are no inheritance children, or if all
- * children are foreign tables that don't support ANALYZE.
+ * We fail and return zero if there are no inheritance children, if all
+ * children are foreign tables that don't support ANALYZE, or if skip_locked
+ * is true and we cannot obtain a lock on all children without waiting.
+ *
+ * If skipped is supplied, it will be set to true if skip_locked takes effect
+ * (false otherwise).
  */
 static int
 acquire_inherited_sample_rows(Relation onerel, int elevel,
 							  HeapTuple *rows, int targrows,
-							  double *totalrows, double *totaldeadrows)
+							  double *totalrows, double *totaldeadrows,
+							  bool skip_locked, bool *skipped)
 {
 	List	   *tableOIDs;
 	Relation   *rels;
@@ -1334,7 +1355,26 @@ acquire_inherited_sample_rows(Relation onerel, int elevel,
 	 * the children.
 	 */
 	tableOIDs =
-		find_all_inheritors(RelationGetRelid(onerel), AccessShareLock, NULL, false);
+		find_all_inheritors(RelationGetRelid(onerel), AccessShareLock, NULL, skip_locked);
+
+	/*
+	 * If tableOIDs is NIL, skip_locked took effect.  In that case, we should
+	 * fail, being sure to set skipped if it is provided.
+	 */
+	if (tableOIDs == NIL)
+	{
+		if (skipped != NULL)
+			*skipped = true;
+
+		return 0;
+	}
+
+	/*
+	 * All skip_locked-related logic precedes this point, so we can just set
+	 * skipped to false if it is provided.
+	 */
+	if (skipped != NULL)
+		*skipped = false;
 
 	/*
 	 * Check that there's at least one descendant, else fail.  This could
-- 
2.16.2

