From d5353fa452d342e970a3aa96d8c6d3ad2d15a089 Mon Sep 17 00:00:00 2001
From: Asim R P <pasim@vmware.com>
Date: Mon, 31 Aug 2020 19:41:01 +0530
Subject: [PATCH 3/6] Add syntax to declare a step that is expected to block

The syntax is (note the "&" suffix):

    permutation "step_1" "step_2"& "step_3"

This is useful for defining steps that are expected to block for reasons
other than waiting on a lock.  For example, an injected fault may cause
a backend to suspend until another event occurs.  Isolation tester will
move on to execute step_3 without waiting for step_2 to finish, because
it is expected to block.

I've incorporated review feedback from Alvaro Herrera and
Michael Paquier.
---
 src/test/isolation/isolationtester.c | 31 ++++++++++++++++-----------
 src/test/isolation/isolationtester.h | 11 ++++++++--
 src/test/isolation/specparse.y       | 32 ++++++++++++++++++++++------
 src/test/isolation/specscanner.l     |  8 +++++++
 4 files changed, 60 insertions(+), 22 deletions(-)

diff --git a/src/test/isolation/isolationtester.c b/src/test/isolation/isolationtester.c
index f80261c0229..896d150189a 100644
--- a/src/test/isolation/isolationtester.c
+++ b/src/test/isolation/isolationtester.c
@@ -345,7 +345,7 @@ run_named_permutations(TestSpec *testspec)
 		/* Find all the named steps using the lookup table */
 		for (j = 0; j < p->nsteps; j++)
 		{
-			Step	  **this = (Step **) bsearch(p->stepnames[j],
+			Step	  **this = (Step **) bsearch(p->steps[j].name,
 												 testspec->allsteps,
 												 testspec->nallsteps,
 												 sizeof(Step *),
@@ -354,10 +354,11 @@ run_named_permutations(TestSpec *testspec)
 			if (this == NULL)
 			{
 				fprintf(stderr, "undefined step \"%s\" specified in permutation\n",
-						p->stepnames[j]);
+						p->steps[j].name);
 				exit(1);
 			}
 			steps[j] = *this;
+			steps[j]->blocks = p->steps[j].blocks;
 		}
 
 		/* And run them */
@@ -726,19 +727,23 @@ try_complete_step(TestSpec *testspec, Step *step, int flags)
 			if (flags & STEP_NONBLOCK)
 			{
 				bool		waiting;
-
-				res = PQexecPrepared(conns[0], PREP_WAITING, 1,
-									 &backend_pid_strs[step->session + 1],
-									 NULL, NULL, 0);
-				if (PQresultStatus(res) != PGRES_TUPLES_OK ||
-					PQntuples(res) != 1)
+				if (step->blocks)
+					waiting = true;
+				else
 				{
-					fprintf(stderr, "lock wait query failed: %s",
-							PQerrorMessage(conns[0]));
-					exit(1);
+					res = PQexecPrepared(conns[0], PREP_WAITING, 1,
+										 &backend_pid_strs[step->session + 1],
+										 NULL, NULL, 0);
+					if (PQresultStatus(res) != PGRES_TUPLES_OK ||
+						PQntuples(res) != 1)
+					{
+						fprintf(stderr, "lock wait query failed: %s",
+								PQerrorMessage(conns[0]));
+						exit(1);
+					}
+					waiting = ((PQgetvalue(res, 0, 0))[0] == 't');
+					PQclear(res);
 				}
-				waiting = ((PQgetvalue(res, 0, 0))[0] == 't');
-				PQclear(res);
 
 				if (waiting)	/* waiting to acquire a lock */
 				{
diff --git a/src/test/isolation/isolationtester.h b/src/test/isolation/isolationtester.h
index 9cf50124168..4b39b421276 100644
--- a/src/test/isolation/isolationtester.h
+++ b/src/test/isolation/isolationtester.h
@@ -30,6 +30,7 @@ struct Step
 {
 	int			session;
 	bool		used;
+	bool		blocks;
 	char	   *name;
 	char	   *sql;
 	char	   *errormsg;
@@ -37,8 +38,14 @@ struct Step
 
 typedef struct
 {
-	int			nsteps;
-	char	  **stepnames;
+	char	   *name;
+	bool		blocks;
+} PermutationStep;
+
+typedef struct
+{
+	int nsteps;
+	PermutationStep	*steps;
 } Permutation;
 
 typedef struct
diff --git a/src/test/isolation/specparse.y b/src/test/isolation/specparse.y
index 5e007e1bf09..7c6832cec54 100644
--- a/src/test/isolation/specparse.y
+++ b/src/test/isolation/specparse.y
@@ -44,8 +44,8 @@ TestSpec		parseresult;			/* result of parsing is left here */
 %type <step> step
 %type <permutation> permutation
 
-%token <str> sqlblock string_literal
-%token PERMUTATION SESSION SETUP STEP TEARDOWN TEST
+%token <str> sqlblock string_literal string_with_blocks
+%token BLOCKING PERMUTATION SESSION SETUP STEP TEARDOWN TEST
 
 %%
 
@@ -143,6 +143,7 @@ step:
 			STEP string_literal sqlblock
 			{
 				$$ = pg_malloc(sizeof(Step));
+				$$->blocks = false;
 				$$->name = $2;
 				$$->sql = $3;
 				$$->used = false;
@@ -183,7 +184,7 @@ permutation:
 			PERMUTATION string_literal_list
 			{
 				$$ = pg_malloc(sizeof(Permutation));
-				$$->stepnames = (char **) $2.elements;
+				$$->steps = (PermutationStep *) $2.elements;
 				$$->nsteps = $2.nelements;
 			}
 		;
@@ -192,15 +193,32 @@ string_literal_list:
 			string_literal_list string_literal
 			{
 				$$.elements = pg_realloc($1.elements,
-										 ($1.nelements + 1) * sizeof(void *));
-				$$.elements[$1.nelements] = $2;
+										 ($1.nelements + 1) * sizeof(PermutationStep));
+				((PermutationStep *) ($$.elements))[$1.nelements].name = $2;
+				((PermutationStep *) ($$.elements))[$1.nelements].blocks = false;
 				$$.nelements = $1.nelements + 1;
 			}
 			| string_literal
 			{
 				$$.nelements = 1;
-				$$.elements = pg_malloc(sizeof(void *));
-				$$.elements[0] = $1;
+				$$.elements = pg_malloc(sizeof(PermutationStep));
+				((PermutationStep *) ($$.elements))[0].name = $1;
+				((PermutationStep *) ($$.elements))[0].blocks = false;
+			}
+			| string_literal_list string_with_blocks
+			{
+				$$.elements = pg_realloc($1.elements,
+										 ($1.nelements + 1) * sizeof(PermutationStep));
+				((PermutationStep *) ($$.elements))[$1.nelements].name = $2;
+				((PermutationStep *) ($$.elements))[$1.nelements].blocks = true;
+				$$.nelements = $1.nelements + 1;
+			}
+			| string_with_blocks
+			{
+				$$.nelements = 1;
+				$$.elements = pg_malloc(sizeof(PermutationStep));
+				((PermutationStep *) ($$.elements))[0].name = $1;
+				((PermutationStep *) ($$.elements))[0].blocks = true;
 			}
 		;
 
diff --git a/src/test/isolation/specscanner.l b/src/test/isolation/specscanner.l
index 410f17727e1..a3848db7674 100644
--- a/src/test/isolation/specscanner.l
+++ b/src/test/isolation/specscanner.l
@@ -39,6 +39,8 @@ static void addlitchar(char c);
 non_newline		[^\n\r]
 space			[ \t\r\f]
 
+blocks			[&]
+
 comment			("#"{non_newline}*)
 
 %%
@@ -69,6 +71,12 @@ teardown		{ return TEARDOWN; }
 					BEGIN(INITIAL);
 					return(string_literal);
 				}
+<qstr>\"{blocks}		{
+					litbuf[litbufpos] = '\0';
+					yylval.str = pg_strdup(litbuf);
+					BEGIN(INITIAL);
+					return(string_with_blocks);
+				}
 <qstr>.			{ addlitchar(yytext[0]); }
 <qstr>\n		{ yyerror("unexpected newline in quoted string"); }
 <qstr><<EOF>>	{ yyerror("unterminated quoted string"); }
-- 
2.24.3 (Apple Git-128)

