isotester-allow-invalid-perms.patch
application/octet-stream
Filename: isotester-allow-invalid-perms.patch
Type: application/octet-stream
Part: 0
Patch
Same data as JSON:
GET /api/v1/attachments/:id/patch
the parsed metadata as JSON — format, series position, per-file stats; never the diff bytes.
API reference →
Format: unified
| File | + | − |
|---|---|---|
| src/test/isolation/isolationtester.c | 61 | 2 |
| src/test/isolation/README | 5 | 3 |
diff --git a/src/test/isolation/README b/src/test/isolation/README
index aeef7f6..2c17876 100644
--- a/src/test/isolation/README
+++ b/src/test/isolation/README
@@ -75,9 +75,11 @@ Support for blocking commands
Each spec may contain commands that block until further action has been taken
(most likely, some other session runs a step that unblocks it or causes a
-deadlock). Such a spec needs to be careful to manually specify valid
-permutations, i.e. those that would not expect a blocked session to execute a
-command. If the spec fails to follow that rule, the spec is aborted.
+deadlock). In case one permutation is detected to require running a command on
+a session that's blocked by a previous step, this is reported and the
+permutation is aborted; the spec continues with the next permutation. The spec
+may be careful to specify only permutations that do not cause this problem
+(saving some run time), but this is not a hard requirement.
Only one command can be waiting at a time. As long as one command is waiting,
other commands are run to completion synchronously.
diff --git a/src/test/isolation/isolationtester.c b/src/test/isolation/isolationtester.c
index b1d49c8..6d8b78b 100644
--- a/src/test/isolation/isolationtester.c
+++ b/src/test/isolation/isolationtester.c
@@ -50,6 +50,8 @@ static int step_bsearch_cmp(const void *a, const void *b);
static void printResultSet(PGresult *res);
+static void report_invalid_permutation(Step *step);
+
/* close all connections and exit */
static void
exit_nicely(void)
@@ -479,11 +481,38 @@ run_permutation(TestSpec * testspec, int nsteps, Step ** steps)
for (i = 0; i < nsteps; i++)
{
Step *step = steps[i];
+ PGconn *conn = conns[1 + step->session];
+
+ /*
+ * Found an invalid permutation: one that requires running a command
+ * on a blocked session. This can never happen in reality. Report the
+ * failure, abort the current permutation, and continue with the next
+ * permutation.
+ */
+ if (waiting != NULL && step->session == waiting->session)
+ {
+ int j;
+
+ report_invalid_permutation(step);
+
+ /*
+ * Finally, complete all running transactions to ensure teardown
+ * doesn't block. Note we don't roll back the control connection.
+ */
+ for (j = 1; j < nconns; j++)
+ {
+ res = PQexec(conns[j], "ROLLBACK");
+ if (res != NULL)
+ PQclear(res);
+ }
- if (!PQsendQuery(conns[1 + step->session], step->sql))
+ goto teardown;
+ }
+
+ if (!PQsendQuery(conn, step->sql))
{
fprintf(stdout, "failed to send query for step %s: %s\n",
- step->name, PQerrorMessage(conns[1 + step->session]));
+ step->name, PQerrorMessage(conn));
exit_nicely();
}
@@ -519,6 +548,7 @@ run_permutation(TestSpec * testspec, int nsteps, Step ** steps)
report_error_message(waiting);
}
+teardown:
/* Perform per-session teardown */
for (i = 0; i < testspec->nsessions; i++)
{
@@ -687,3 +717,32 @@ printResultSet(PGresult *res)
printf("\n");
}
}
+
+static void
+report_invalid_permutation(Step *step)
+{
+ PGconn *conn = conns[1 + step->session];
+ PGcancel *cancel;
+ PGresult *res;
+
+ fprintf(stdout, "step %s: invalid permutation detected, skipping\n", step->name);
+
+ /* Cancel the waiting statement from this session. */
+ cancel = PQgetCancel(conn);
+ if (cancel)
+ {
+ char buf[256];
+
+ if (PQcancel(cancel, buf, sizeof(buf)) != 1)
+ {
+ fprintf(stdout, "failed to cancel query: %s\n", buf);
+ exit_nicely();
+ }
+
+ /* Be sure to consume whatever is left in the connection */
+ while ((res = PQgetResult(conn)) != NULL)
+ PQclear(res);
+
+ PQfreeCancel(cancel);
+ }
+}