v7-0009-Skip-ANALYZE-with-VACOPT_SKIP_LOCKED-if-acquire_i.patch

application/octet-stream

Filename: v7-0009-Skip-ANALYZE-with-VACOPT_SKIP_LOCKED-if-acquire_i.patch
Type: application/octet-stream
Part: 8
Message: Re: BUG #14941: Vacuum crashes

Patch

Format: format-patch
Series: patch v7-0009
Subject: Skip ANALYZE with VACOPT_SKIP_LOCKED if acquire_inherited_sample_rows() blocks.
File+
src/backend/commands/analyze.c 47 7
From 7ad5ee333bc8fee0c860be2ad537eeb5d5d728ce Mon Sep 17 00:00:00 2001
From: Nathan Bossart <bossartn@amazon.com>
Date: Thu, 5 Apr 2018 18:43:45 +0000
Subject: [PATCH v7 09/12] Skip ANALYZE with VACOPT_SKIP_LOCKED if
 acquire_inherited_sample_rows() blocks.

---
 src/backend/commands/analyze.c | 54 ++++++++++++++++++++++++++++++++++++------
 1 file changed, 47 insertions(+), 7 deletions(-)

diff --git a/src/backend/commands/analyze.c b/src/backend/commands/analyze.c
index 0421d77ad7..1997726fd1 100644
--- a/src/backend/commands/analyze.c
+++ b/src/backend/commands/analyze.c
@@ -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);
@@ -353,6 +354,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,
@@ -550,9 +552,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,
@@ -1337,15 +1353,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;
@@ -1363,7 +1384,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