From d5353fa452d342e970a3aa96d8c6d3ad2d15a089 Mon Sep 17 00:00:00 2001 From: Asim R P 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 %type permutation -%token sqlblock string_literal -%token PERMUTATION SESSION SETUP STEP TEARDOWN TEST +%token 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); } +\"{blocks} { + litbuf[litbufpos] = '\0'; + yylval.str = pg_strdup(litbuf); + BEGIN(INITIAL); + return(string_with_blocks); + } . { addlitchar(yytext[0]); } \n { yyerror("unexpected newline in quoted string"); } <> { yyerror("unterminated quoted string"); } -- 2.24.3 (Apple Git-128)