fklocks-tests-harden.patch
text/plain
Filename: fklocks-tests-harden.patch
Type: text/plain
Part: 0
Message:
Re: FOR KEY LOCK foreign keys
diff --git a/src/test/isolation/isolationtester.c b/src/test/isolation/isolationtester.c
index 126e185..96d7f17 100644
*** a/src/test/isolation/isolationtester.c
--- b/src/test/isolation/isolationtester.c
***************
*** 21,26 ****
--- 21,27 ----
#endif
#include "libpq-fe.h"
+ #include "pqexpbuffer.h"
#include "isolationtester.h"
***************
*** 31,37 ****
* connections represent spec-defined sessions.
*/
static PGconn **conns = NULL;
! static const char **backend_ids = NULL;
static int nconns = 0;
static void run_all_permutations(TestSpec * testspec);
--- 32,38 ----
* connections represent spec-defined sessions.
*/
static PGconn **conns = NULL;
! static const char **backend_pids = NULL;
static int nconns = 0;
static void run_all_permutations(TestSpec * testspec);
***************
*** 67,72 **** main(int argc, char **argv)
--- 68,74 ----
TestSpec *testspec;
int i;
PGresult *res;
+ PQExpBufferData wait_query;
/*
* If the user supplies a parameter on the command line, use it as the
***************
*** 89,95 **** main(int argc, char **argv)
*/
nconns = 1 + testspec->nsessions;
conns = calloc(nconns, sizeof(PGconn *));
! backend_ids = calloc(nconns, sizeof(*backend_ids));
for (i = 0; i < nconns; i++)
{
conns[i] = PQconnectdb(conninfo);
--- 91,97 ----
*/
nconns = 1 + testspec->nsessions;
conns = calloc(nconns, sizeof(PGconn *));
! backend_pids = calloc(nconns, sizeof(*backend_pids));
for (i = 0; i < nconns; i++)
{
conns[i] = PQconnectdb(conninfo);
***************
*** 112,134 **** main(int argc, char **argv)
}
PQclear(res);
! /* Get the backend ID for lock wait checking. */
! res = PQexec(conns[i], "SELECT i FROM pg_stat_get_backend_idset() t(i) "
! "WHERE pg_stat_get_backend_pid(i) = pg_backend_pid()");
if (PQresultStatus(res) == PGRES_TUPLES_OK)
{
if (PQntuples(res) == 1 && PQnfields(res) == 1)
! backend_ids[i] = strdup(PQgetvalue(res, 0, 0));
else
{
! fprintf(stderr, "backend id query returned %d rows and %d columns, expected 1 row and 1 column",
PQntuples(res), PQnfields(res));
exit_nicely();
}
}
else
{
! fprintf(stderr, "backend id query failed: %s",
PQerrorMessage(conns[i]));
exit_nicely();
}
--- 114,135 ----
}
PQclear(res);
! /* Get the backend pid for lock wait checking. */
! res = PQexec(conns[i], "SELECT pg_backend_pid()");
if (PQresultStatus(res) == PGRES_TUPLES_OK)
{
if (PQntuples(res) == 1 && PQnfields(res) == 1)
! backend_pids[i] = strdup(PQgetvalue(res, 0, 0));
else
{
! fprintf(stderr, "backend pid query returned %d rows and %d columns, expected 1 row and 1 column",
PQntuples(res), PQnfields(res));
exit_nicely();
}
}
else
{
! fprintf(stderr, "backend pid query failed: %s",
PQerrorMessage(conns[i]));
exit_nicely();
}
***************
*** 145,152 **** main(int argc, char **argv)
session->steps[stepindex]->session = i;
}
! res = PQprepare(conns[0], PREP_WAITING,
! "SELECT 1 WHERE pg_stat_get_backend_waiting($1)", 0, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "prepare of lock wait query failed: %s",
--- 146,232 ----
session->steps[stepindex]->session = i;
}
! /*
! * Build the query we'll use to detect lock contention among sessions in
! * the test specification. Most of the time, we could get away with
! * simply checking whether a session is waiting for *any* lock: we don't
! * exactly expect concurrent use of test tables. However, autovacuum will
! * occasionally take AccessExclusiveLock to truncate a table, and we must
! * ignore that transient wait.
! */
! initPQExpBuffer(&wait_query);
! appendPQExpBufferStr(&wait_query,
! "SELECT 1 FROM pg_locks holder, pg_locks waiter "
! "WHERE NOT waiter.granted AND waiter.pid = $1 "
! "AND holder.granted "
! "AND holder.pid <> $1 AND holder.pid IN (");
! /* The spec syntax requires at least one session; assume that here. */
! appendPQExpBuffer(&wait_query, "%s", backend_pids[1]);
! for (i = 2; i < nconns; i++)
! appendPQExpBuffer(&wait_query, ", %s", backend_pids[i]);
! appendPQExpBufferStr(&wait_query,
! ") "
!
! "AND holder.mode = ANY (CASE waiter.mode "
! "WHEN 'AccessShareLock' THEN ARRAY["
! "'AccessExclusiveLock'] "
! "WHEN 'RowShareLock' THEN ARRAY["
! "'ExclusiveLock',"
! "'AccessExclusiveLock'] "
! "WHEN 'RowExclusiveLock' THEN ARRAY["
! "'ShareLock',"
! "'ShareRowExclusiveLock',"
! "'ExclusiveLock',"
! "'AccessExclusiveLock'] "
! "WHEN 'ShareUpdateExclusiveLock' THEN ARRAY["
! "'ShareUpdateExclusiveLock',"
! "'ShareLock',"
! "'ShareRowExclusiveLock',"
! "'ExclusiveLock',"
! "'AccessExclusiveLock'] "
! "WHEN 'ShareLock' THEN ARRAY["
! "'RowExclusiveLock',"
! "'ShareUpdateExclusiveLock',"
! "'ShareRowExclusiveLock',"
! "'ExclusiveLock',"
! "'AccessExclusiveLock'] "
! "WHEN 'ShareRowExclusiveLock' THEN ARRAY["
! "'RowExclusiveLock',"
! "'ShareUpdateExclusiveLock',"
! "'ShareLock',"
! "'ShareRowExclusiveLock',"
! "'ExclusiveLock',"
! "'AccessExclusiveLock'] "
! "WHEN 'ExclusiveLock' THEN ARRAY["
! "'RowShareLock',"
! "'RowExclusiveLock',"
! "'ShareUpdateExclusiveLock',"
! "'ShareLock',"
! "'ShareRowExclusiveLock',"
! "'ExclusiveLock',"
! "'AccessExclusiveLock'] "
! "WHEN 'AccessExclusiveLock' THEN ARRAY["
! "'AccessShareLock',"
! "'RowShareLock',"
! "'RowExclusiveLock',"
! "'ShareUpdateExclusiveLock',"
! "'ShareLock',"
! "'ShareRowExclusiveLock',"
! "'ExclusiveLock',"
! "'AccessExclusiveLock'] END) "
!
! "AND holder.locktype IS NOT DISTINCT FROM waiter.locktype "
! "AND holder.database IS NOT DISTINCT FROM waiter.database "
! "AND holder.relation IS NOT DISTINCT FROM waiter.relation "
! "AND holder.page IS NOT DISTINCT FROM waiter.page "
! "AND holder.tuple IS NOT DISTINCT FROM waiter.tuple "
! "AND holder.virtualxid IS NOT DISTINCT FROM waiter.virtualxid "
! "AND holder.transactionid IS NOT DISTINCT FROM waiter.transactionid "
! "AND holder.classid IS NOT DISTINCT FROM waiter.classid "
! "AND holder.objid IS NOT DISTINCT FROM waiter.objid "
! "AND holder.objsubid IS NOT DISTINCT FROM waiter.objsubid ");
!
! res = PQprepare(conns[0], PREP_WAITING, wait_query.data, 0, NULL);
if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
fprintf(stderr, "prepare of lock wait query failed: %s",
***************
*** 154,159 **** main(int argc, char **argv)
--- 234,240 ----
exit_nicely();
}
PQclear(res);
+ termPQExpBuffer(&wait_query);
/*
* Run the permutations specified in the spec, or all if none were
***************
*** 411,419 **** run_permutation(TestSpec * testspec, int nsteps, Step ** steps)
* Our caller already sent the query associated with this step. Wait for it
* to either complete or (if given the STEP_NONBLOCK flag) to block while
* waiting for a lock. We assume that any lock wait will persist until we
! * have executed additional steps in the permutation. This is not fully
! * robust -- a concurrent autovacuum could briefly take a lock with which we
! * conflict. The risk may be low enough to discount.
*
* When calling this function on behalf of a given step for a second or later
* time, pass the STEP_RETRY flag. This only affects the messages printed.
--- 492,498 ----
* Our caller already sent the query associated with this step. Wait for it
* to either complete or (if given the STEP_NONBLOCK flag) to block while
* waiting for a lock. We assume that any lock wait will persist until we
! * have executed additional steps in the permutation.
*
* When calling this function on behalf of a given step for a second or later
* time, pass the STEP_RETRY flag. This only affects the messages printed.
***************
*** 450,456 **** try_complete_step(Step *step, int flags)
int ntuples;
res = PQexecPrepared(conns[0], PREP_WAITING, 1,
! &backend_ids[step->session + 1],
NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
--- 529,535 ----
int ntuples;
res = PQexecPrepared(conns[0], PREP_WAITING, 1,
! &backend_pids[step->session + 1],
NULL, NULL, 0);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
diff --git a/src/test/isolation/specs/fk-deindex b533d77..9f46c6b 100644
*** a/src/test/isolation/specs/fk-deadlock.spec
--- b/src/test/isolation/specs/fk-deadlock.spec
***************
*** 19,25 **** teardown
}
session "s1"
! setup { BEGIN; SET deadlock_timeout = '20ms'; }
step "s1i" { INSERT INTO child VALUES (1, 1); }
step "s1u" { UPDATE parent SET aux = 'bar'; }
step "s1c" { COMMIT; }
--- 19,25 ----
}
session "s1"
! setup { BEGIN; SET deadlock_timeout = '100ms'; }
step "s1i" { INSERT INTO child VALUES (1, 1); }
step "s1u" { UPDATE parent SET aux = 'bar'; }
step "s1c" { COMMIT; }
diff --git a/src/test/isolation/specs/fk-deadlocindex 5653628..a8f1516 100644
*** a/src/test/isolation/specs/fk-deadlock2.spec
--- b/src/test/isolation/specs/fk-deadlock2.spec
***************
*** 24,30 **** teardown
}
session "s1"
! setup { BEGIN; SET deadlock_timeout = '20ms'; }
step "s1u1" { UPDATE A SET Col1 = 1 WHERE AID = 1; }
step "s1u2" { UPDATE B SET Col2 = 1 WHERE BID = 2; }
step "s1c" { COMMIT; }
--- 24,30 ----
}
session "s1"
! setup { BEGIN; SET deadlock_timeout = '100ms'; }
step "s1u1" { UPDATE A SET Col1 = 1 WHERE AID = 1; }
step "s1u2" { UPDATE B SET Col2 = 1 WHERE BID = 2; }
step "s1c" { COMMIT; }