Age Owner TLA Line data Source code
1 : /*
2 : * src/test/isolation/isolationtester.c
3 : *
4 : * isolationtester.c
5 : * Runs an isolation test specified by a spec file.
6 : */
7 :
8 : #include "postgres_fe.h"
9 :
10 : #include <sys/select.h>
11 : #include <sys/time.h>
12 :
13 : #include "datatype/timestamp.h"
14 : #include "isolationtester.h"
15 : #include "libpq-fe.h"
16 : #include "pg_getopt.h"
17 : #include "pqexpbuffer.h"
18 :
19 : #define PREP_WAITING "isolationtester_waiting"
20 :
21 : /*
22 : * conns[0] is the global setup, teardown, and watchdog connection. Additional
23 : * connections represent spec-defined sessions.
24 : */
25 : typedef struct IsoConnInfo
26 : {
27 : /* The libpq connection object for this connection. */
28 : PGconn *conn;
29 : /* The backend PID, in numeric and string formats. */
30 : int backend_pid;
31 : const char *backend_pid_str;
32 : /* Name of the associated session. */
33 : const char *sessionname;
34 : /* Active step on this connection, or NULL if idle. */
35 : PermutationStep *active_step;
36 : /* Number of NOTICE messages received from connection. */
37 : int total_notices;
38 : } IsoConnInfo;
39 :
40 : static IsoConnInfo *conns = NULL;
41 : static int nconns = 0;
42 :
43 : /* Flag indicating some new NOTICE has arrived */
44 : static bool any_new_notice = false;
45 :
46 : /* Maximum time to wait before giving up on a step (in usec) */
47 : static int64 max_step_wait = 360 * USECS_PER_SEC;
48 :
49 :
50 : static void check_testspec(TestSpec *testspec);
51 : static void run_testspec(TestSpec *testspec);
52 : static void run_all_permutations(TestSpec *testspec);
53 : static void run_all_permutations_recurse(TestSpec *testspec, int *piles,
54 : int nsteps, PermutationStep **steps);
55 : static void run_named_permutations(TestSpec *testspec);
56 : static void run_permutation(TestSpec *testspec, int nsteps,
57 : PermutationStep **steps);
58 :
59 : /* Flag bits for try_complete_step(s) */
60 : #define STEP_NONBLOCK 0x1 /* return as soon as cmd waits for a lock */
61 : #define STEP_RETRY 0x2 /* this is a retry of a previously-waiting cmd */
62 :
63 : static int try_complete_steps(TestSpec *testspec, PermutationStep **waiting,
64 : int nwaiting, int flags);
65 : static bool try_complete_step(TestSpec *testspec, PermutationStep *pstep,
66 : int flags);
67 :
68 : static int step_qsort_cmp(const void *a, const void *b);
69 : static int step_bsearch_cmp(const void *a, const void *b);
70 :
71 : static bool step_has_blocker(PermutationStep *pstep);
72 : static void printResultSet(PGresult *res);
73 : static void isotesterNoticeProcessor(void *arg, const char *message);
74 : static void blackholeNoticeProcessor(void *arg, const char *message);
4444 heikki.linnakangas 75 ECB :
76 : static void
1555 peter 77 GIC 131 : disconnect_atexit(void)
78 : {
4444 heikki.linnakangas 79 ECB : int i;
4382 bruce 80 :
4444 heikki.linnakangas 81 CBC 582 : for (i = 0; i < nconns; i++)
656 tgl 82 451 : if (conns[i].conn)
656 tgl 83 GIC 451 : PQfinish(conns[i].conn);
4444 heikki.linnakangas 84 131 : }
4444 heikki.linnakangas 85 ECB :
86 : int
4444 heikki.linnakangas 87 GIC 138 : main(int argc, char **argv)
88 : {
89 : const char *conninfo;
90 : const char *env_wait;
91 : TestSpec *testspec;
92 : PGresult *res;
93 : PQExpBufferData wait_query;
94 : int opt;
656 tgl 95 ECB : int i;
96 :
1324 michael 97 CBC 138 : while ((opt = getopt(argc, argv, "V")) != -1)
98 : {
4175 alvherre 99 7 : switch (opt)
4175 alvherre 100 ECB : {
3439 rhaas 101 CBC 7 : case 'V':
3439 rhaas 102 GBC 7 : puts("isolationtester (PostgreSQL) " PG_VERSION);
103 7 : exit(0);
4175 alvherre 104 UBC 0 : default:
1324 michael 105 UIC 0 : fprintf(stderr, "Usage: isolationtester [CONNINFO]\n");
4175 alvherre 106 0 : return EXIT_FAILURE;
107 : }
108 : }
109 :
110 : /*
111 : * Make stdout unbuffered to match stderr; and ensure stderr is unbuffered
3398 alvherre 112 ECB : * too, which it should already be everywhere except sometimes in Windows.
113 : */
3398 alvherre 114 GIC 131 : setbuf(stdout, NULL);
115 131 : setbuf(stderr, NULL);
116 :
117 : /*
118 : * If the user supplies a non-option parameter on the command line, use it
119 : * as the conninfo string; otherwise default to setting dbname=postgres
120 : * and using environment variables or defaults for all other connection
4175 alvherre 121 ECB : * parameters.
4444 heikki.linnakangas 122 : */
4175 alvherre 123 GIC 131 : if (argc > optind)
4175 alvherre 124 GBC 131 : conninfo = argv[optind];
125 : else
4444 heikki.linnakangas 126 UIC 0 : conninfo = "dbname = postgres";
127 :
128 : /*
129 : * If PG_TEST_TIMEOUT_DEFAULT is set, adopt its value (given in seconds)
130 : * as half the max time to wait for any one step to complete.
1217 tgl 131 ECB : */
282 noah 132 GNC 131 : env_wait = getenv("PG_TEST_TIMEOUT_DEFAULT");
1217 tgl 133 GIC 131 : if (env_wait != NULL)
282 noah 134 UNC 0 : max_step_wait = 2 * ((int64) atoi(env_wait)) * USECS_PER_SEC;
1217 tgl 135 ECB :
4444 heikki.linnakangas 136 : /* Read the test spec from stdin */
4444 heikki.linnakangas 137 GIC 131 : spec_yyparse();
138 131 : testspec = &parseresult;
4175 alvherre 139 ECB :
140 : /* Perform post-parse checking, and fill in linking fields */
656 tgl 141 CBC 131 : check_testspec(testspec);
142 :
4444 heikki.linnakangas 143 GIC 131 : printf("Parsed test spec with %d sessions\n", testspec->nsessions);
144 :
145 : /*
146 : * Establish connections to the database, one for each session and an
3955 bruce 147 ECB : * extra for lock wait detection and global work.
4289 alvherre 148 : */
4289 alvherre 149 CBC 131 : nconns = 1 + testspec->nsessions;
656 tgl 150 GIC 131 : conns = (IsoConnInfo *) pg_malloc0(nconns * sizeof(IsoConnInfo));
1555 peter 151 CBC 131 : atexit(disconnect_atexit);
152 :
4289 alvherre 153 GIC 582 : for (i = 0; i < nconns; i++)
154 : {
482 andres 155 ECB : const char *sessionname;
156 :
656 tgl 157 GIC 451 : if (i == 0)
482 andres 158 CBC 131 : sessionname = "control connection";
159 : else
160 320 : sessionname = testspec->sessions[i - 1]->name;
161 :
162 451 : conns[i].sessionname = sessionname;
656 tgl 163 ECB :
656 tgl 164 GIC 451 : conns[i].conn = PQconnectdb(conninfo);
656 tgl 165 GBC 451 : if (PQstatus(conns[i].conn) != CONNECTION_OK)
4444 heikki.linnakangas 166 EUB : {
807 tgl 167 UBC 0 : fprintf(stderr, "Connection %d failed: %s",
656 tgl 168 UIC 0 : i, PQerrorMessage(conns[i].conn));
1555 peter 169 0 : exit(1);
170 : }
171 :
172 : /*
173 : * Set up notice processors for the user-defined connections, so that
174 : * messages can get printed prefixed with the session names. The
175 : * control connection gets a "blackhole" processor instead (hides all
1612 alvherre 176 ECB : * messages).
177 : */
1612 alvherre 178 GIC 451 : if (i != 0)
656 tgl 179 CBC 320 : PQsetNoticeProcessor(conns[i].conn,
180 : isotesterNoticeProcessor,
181 320 : (void *) &conns[i]);
182 : else
656 tgl 183 GIC 131 : PQsetNoticeProcessor(conns[i].conn,
184 : blackholeNoticeProcessor,
185 : NULL);
186 :
187 : /*
188 : * Similarly, append the session name to application_name to make it
189 : * easier to map spec file sessions to log output and
190 : * pg_stat_activity. The reason to append instead of just setting the
482 andres 191 ECB : * name is that we don't know the name of the test currently running.
192 : */
482 andres 193 GIC 451 : res = PQexecParams(conns[i].conn,
194 : "SELECT set_config('application_name',\n"
195 : " current_setting('application_name') || '/' || $1,\n"
196 : " false)",
197 : 1, NULL,
482 andres 198 ECB : &sessionname,
199 : NULL, NULL, 0);
482 andres 200 GBC 451 : if (PQresultStatus(res) != PGRES_TUPLES_OK)
482 andres 201 EUB : {
482 andres 202 UBC 0 : fprintf(stderr, "setting of application name failed: %s",
482 andres 203 UIC 0 : PQerrorMessage(conns[i].conn));
204 0 : exit(1);
205 : }
482 andres 206 ECB :
1351 tgl 207 : /* Save each connection's backend PID for subsequent use. */
656 tgl 208 GIC 451 : conns[i].backend_pid = PQbackendPID(conns[i].conn);
209 451 : conns[i].backend_pid_str = psprintf("%d", conns[i].backend_pid);
210 : }
211 :
212 : /*
213 : * Build the query we'll use to detect lock contention among sessions in
214 : * the test specification. Most of the time, we could get away with
215 : * simply checking whether a session is waiting for *any* lock: we don't
216 : * exactly expect concurrent use of test tables. However, autovacuum will
217 : * occasionally take AccessExclusiveLock to truncate a table, and we must
4282 alvherre 218 ECB : * ignore that transient wait.
219 : */
4282 alvherre 220 GIC 131 : initPQExpBuffer(&wait_query);
221 131 : appendPQExpBufferStr(&wait_query,
2118 tgl 222 ECB : "SELECT pg_catalog.pg_isolation_test_session_is_blocked($1, '{");
4282 alvherre 223 : /* The spec syntax requires at least one session; assume that here. */
656 tgl 224 CBC 131 : appendPQExpBufferStr(&wait_query, conns[1].backend_pid_str);
4282 alvherre 225 320 : for (i = 2; i < nconns; i++)
656 tgl 226 GIC 189 : appendPQExpBuffer(&wait_query, ",%s", conns[i].backend_pid_str);
2190 tgl 227 CBC 131 : appendPQExpBufferStr(&wait_query, "}')");
2195 kgrittn 228 ECB :
656 tgl 229 GIC 131 : res = PQprepare(conns[0].conn, PREP_WAITING, wait_query.data, 0, NULL);
4289 alvherre 230 GBC 131 : if (PQresultStatus(res) != PGRES_COMMAND_OK)
4289 alvherre 231 EUB : {
4289 alvherre 232 UBC 0 : fprintf(stderr, "prepare of lock wait query failed: %s",
656 tgl 233 UIC 0 : PQerrorMessage(conns[0].conn));
1555 peter 234 LBC 0 : exit(1);
4289 alvherre 235 ECB : }
4289 alvherre 236 GIC 131 : PQclear(res);
4282 237 131 : termPQExpBuffer(&wait_query);
238 :
239 : /*
240 : * Run the permutations specified in the spec, or all if none were
4444 heikki.linnakangas 241 ECB : * explicitly specified.
242 : */
4175 alvherre 243 CBC 131 : run_testspec(testspec);
244 :
4444 heikki.linnakangas 245 GIC 131 : return 0;
246 : }
247 :
248 : /*
249 : * Validity-check the test spec and fill in cross-links between nodes.
656 tgl 250 ECB : */
251 : static void
656 tgl 252 GIC 131 : check_testspec(TestSpec *testspec)
253 : {
254 : int nallsteps;
255 : Step **allsteps;
256 : int i,
257 : j,
258 : k;
656 tgl 259 ECB :
260 : /* Create a sorted lookup table of all steps. */
656 tgl 261 CBC 131 : nallsteps = 0;
656 tgl 262 GIC 451 : for (i = 0; i < testspec->nsessions; i++)
656 tgl 263 CBC 320 : nallsteps += testspec->sessions[i]->nsteps;
264 :
265 131 : allsteps = pg_malloc(nallsteps * sizeof(Step *));
656 tgl 266 ECB :
656 tgl 267 GIC 131 : k = 0;
656 tgl 268 CBC 451 : for (i = 0; i < testspec->nsessions; i++)
656 tgl 269 ECB : {
656 tgl 270 GIC 1640 : for (j = 0; j < testspec->sessions[i]->nsteps; j++)
271 1320 : allsteps[k++] = testspec->sessions[i]->steps[j];
656 tgl 272 ECB : }
273 :
656 tgl 274 GIC 131 : qsort(allsteps, nallsteps, sizeof(Step *), step_qsort_cmp);
656 tgl 275 ECB :
276 : /* Verify that all step names are unique. */
656 tgl 277 CBC 1320 : for (i = 1; i < nallsteps; i++)
656 tgl 278 ECB : {
656 tgl 279 GIC 1189 : if (strcmp(allsteps[i - 1]->name,
656 tgl 280 GBC 1189 : allsteps[i]->name) == 0)
656 tgl 281 EUB : {
656 tgl 282 UBC 0 : fprintf(stderr, "duplicate step name: %s\n",
656 tgl 283 UIC 0 : allsteps[i]->name);
284 0 : exit(1);
285 : }
286 : }
656 tgl 287 ECB :
288 : /* Set the session index fields in steps. */
656 tgl 289 CBC 451 : for (i = 0; i < testspec->nsessions; i++)
290 : {
291 320 : Session *session = testspec->sessions[i];
656 tgl 292 ECB :
656 tgl 293 GIC 1640 : for (j = 0; j < session->nsteps; j++)
294 1320 : session->steps[j]->session = i;
295 : }
296 :
297 : /*
298 : * If we have manually-specified permutations, link PermutationSteps to
656 tgl 299 ECB : * Steps, and fill in blocker links.
300 : */
656 tgl 301 CBC 1290 : for (i = 0; i < testspec->npermutations; i++)
302 : {
303 1159 : Permutation *p = testspec->permutations[i];
304 :
305 9793 : for (j = 0; j < p->nsteps; j++)
656 tgl 306 ECB : {
656 tgl 307 GIC 8634 : PermutationStep *pstep = p->steps[j];
308 8634 : Step **this = (Step **) bsearch(pstep->name,
309 : allsteps,
310 : nallsteps,
311 : sizeof(Step *),
656 tgl 312 ECB : step_bsearch_cmp);
313 :
656 tgl 314 GBC 8634 : if (this == NULL)
315 : {
656 tgl 316 UBC 0 : fprintf(stderr, "undefined step \"%s\" specified in permutation\n",
317 : pstep->name);
656 tgl 318 LBC 0 : exit(1);
319 : }
656 tgl 320 GIC 8634 : pstep->step = *this;
656 tgl 321 ECB :
322 : /* Mark the step used, for check below */
656 tgl 323 GIC 8634 : pstep->step->used = true;
324 : }
325 :
326 : /*
327 : * Identify any blocker steps. We search only the current
328 : * permutation, since steps not used there couldn't be concurrent.
329 : * Note that it's OK to reference later permutation steps, so this
656 tgl 330 ECB : * can't be combined with the previous loop.
331 : */
656 tgl 332 CBC 9793 : for (j = 0; j < p->nsteps; j++)
333 : {
334 8634 : PermutationStep *pstep = p->steps[j];
335 :
336 8682 : for (k = 0; k < pstep->nblockers; k++)
337 : {
656 tgl 338 GIC 48 : PermutationStepBlocker *blocker = pstep->blockers[k];
656 tgl 339 ECB : int n;
340 :
656 tgl 341 GIC 48 : if (blocker->blocktype == PSB_ONCE)
656 tgl 342 CBC 11 : continue; /* nothing to link to */
656 tgl 343 ECB :
656 tgl 344 GIC 37 : blocker->step = NULL;
656 tgl 345 CBC 162 : for (n = 0; n < p->nsteps; n++)
346 : {
347 162 : PermutationStep *otherp = p->steps[n];
348 :
349 162 : if (strcmp(otherp->name, blocker->stepname) == 0)
656 tgl 350 ECB : {
656 tgl 351 GIC 37 : blocker->step = otherp->step;
352 37 : break;
656 tgl 353 ECB : }
354 : }
656 tgl 355 GBC 37 : if (blocker->step == NULL)
356 : {
656 tgl 357 UBC 0 : fprintf(stderr, "undefined blocking step \"%s\" referenced in permutation step \"%s\"\n",
358 : blocker->stepname, pstep->name);
656 tgl 359 UIC 0 : exit(1);
656 tgl 360 ECB : }
361 : /* can't block on completion of step of own session */
656 tgl 362 GBC 37 : if (blocker->step->session == pstep->step->session)
363 : {
656 tgl 364 UBC 0 : fprintf(stderr, "permutation step \"%s\" cannot block on its own session\n",
365 : pstep->name);
656 tgl 366 UIC 0 : exit(1);
367 : }
368 : }
369 : }
370 : }
371 :
372 : /*
373 : * If we have manually-specified permutations, verify that all steps have
374 : * been used, warning about anything defined but not used. We can skip
656 tgl 375 ECB : * this when using automatically-generated permutations.
376 : */
656 tgl 377 CBC 131 : if (testspec->permutations)
378 : {
379 1361 : for (i = 0; i < nallsteps; i++)
656 tgl 380 ECB : {
656 tgl 381 GIC 1244 : if (!allsteps[i]->used)
382 6 : fprintf(stderr, "unused step name: %s\n", allsteps[i]->name);
383 : }
656 tgl 384 ECB : }
385 :
651 tgl 386 GIC 131 : free(allsteps);
387 131 : }
388 :
389 : /*
390 : * Run the permutations specified in the spec, or all if none were
391 : * explicitly specified.
4175 alvherre 392 ECB : */
393 : static void
3260 bruce 394 CBC 131 : run_testspec(TestSpec *testspec)
4175 alvherre 395 ECB : {
4175 alvherre 396 GIC 131 : if (testspec->permutations)
4175 alvherre 397 CBC 117 : run_named_permutations(testspec);
4175 alvherre 398 ECB : else
4175 alvherre 399 GIC 14 : run_all_permutations(testspec);
400 131 : }
401 :
402 : /*
403 : * Run all permutations of the steps and sessions.
4444 heikki.linnakangas 404 ECB : */
405 : static void
3260 bruce 406 GIC 14 : run_all_permutations(TestSpec *testspec)
407 : {
408 : int nsteps;
409 : int i;
410 : PermutationStep *steps;
411 : PermutationStep **stepptrs;
412 : int *piles;
4444 heikki.linnakangas 413 ECB :
414 : /* Count the total number of steps in all sessions */
4444 heikki.linnakangas 415 CBC 14 : nsteps = 0;
4444 heikki.linnakangas 416 GIC 44 : for (i = 0; i < testspec->nsessions; i++)
417 30 : nsteps += testspec->sessions[i]->nsteps;
4444 heikki.linnakangas 418 ECB :
656 tgl 419 : /* Create PermutationStep workspace array */
656 tgl 420 CBC 14 : steps = (PermutationStep *) pg_malloc0(sizeof(PermutationStep) * nsteps);
421 14 : stepptrs = (PermutationStep **) pg_malloc(sizeof(PermutationStep *) * nsteps);
656 tgl 422 GIC 90 : for (i = 0; i < nsteps; i++)
423 76 : stepptrs[i] = steps + i;
424 :
425 : /*
426 : * To generate the permutations, we conceptually put the steps of each
427 : * session on a pile. To generate a permutation, we pick steps from the
428 : * piles until all piles are empty. By picking steps from piles in
429 : * different order, we get different permutations.
430 : *
431 : * A pile is actually just an integer which tells how many steps we've
4382 bruce 432 ECB : * already picked from this pile.
4444 heikki.linnakangas 433 : */
2413 tgl 434 CBC 14 : piles = pg_malloc(sizeof(int) * testspec->nsessions);
4444 heikki.linnakangas 435 GIC 44 : for (i = 0; i < testspec->nsessions; i++)
4444 heikki.linnakangas 436 CBC 30 : piles[i] = 0;
437 :
651 tgl 438 14 : run_all_permutations_recurse(testspec, piles, 0, stepptrs);
651 tgl 439 ECB :
651 tgl 440 CBC 14 : free(steps);
441 14 : free(stepptrs);
651 tgl 442 GIC 14 : free(piles);
4444 heikki.linnakangas 443 14 : }
4444 heikki.linnakangas 444 ECB :
445 : static void
651 tgl 446 GIC 1560 : run_all_permutations_recurse(TestSpec *testspec, int *piles,
447 : int nsteps, PermutationStep **steps)
4444 heikki.linnakangas 448 ECB : {
449 : int i;
656 tgl 450 CBC 1560 : bool found = false;
451 :
4444 heikki.linnakangas 452 GIC 5601 : for (i = 0; i < testspec->nsessions; i++)
4444 heikki.linnakangas 453 ECB : {
454 : /* If there's any more steps in this pile, pick it and recurse */
4444 heikki.linnakangas 455 CBC 4041 : if (piles[i] < testspec->sessions[i]->nsteps)
456 : {
656 tgl 457 GIC 1546 : Step *newstep = testspec->sessions[i]->steps[piles[i]];
458 :
459 : /*
460 : * These automatically-generated PermutationSteps never have
461 : * blocker conditions. So we need only fill these fields, relying
656 tgl 462 ECB : * on run_all_permutations() to have zeroed the rest:
463 : */
656 tgl 464 GIC 1546 : steps[nsteps]->name = newstep->name;
656 tgl 465 CBC 1546 : steps[nsteps]->step = newstep;
466 :
4444 heikki.linnakangas 467 1546 : piles[i]++;
468 :
651 tgl 469 1546 : run_all_permutations_recurse(testspec, piles, nsteps + 1, steps);
470 :
4444 heikki.linnakangas 471 1546 : piles[i]--;
472 :
656 tgl 473 GIC 1546 : found = true;
474 : }
475 : }
4444 heikki.linnakangas 476 ECB :
477 : /* If all the piles were empty, this permutation is completed. Run it */
4444 heikki.linnakangas 478 CBC 1560 : if (!found)
4444 heikki.linnakangas 479 GIC 486 : run_permutation(testspec, nsteps, steps);
480 1560 : }
481 :
482 : /*
483 : * Run permutations given in the test spec
4444 heikki.linnakangas 484 ECB : */
485 : static void
3260 bruce 486 GIC 117 : run_named_permutations(TestSpec *testspec)
487 : {
656 tgl 488 ECB : int i;
489 :
4444 heikki.linnakangas 490 CBC 1276 : for (i = 0; i < testspec->npermutations; i++)
491 : {
492 1159 : Permutation *p = testspec->permutations[i];
493 :
656 tgl 494 1159 : run_permutation(testspec, p->nsteps, p->steps);
495 : }
4444 heikki.linnakangas 496 GIC 117 : }
4444 heikki.linnakangas 497 ECB :
498 : static int
4444 heikki.linnakangas 499 CBC 4023 : step_qsort_cmp(const void *a, const void *b)
4444 heikki.linnakangas 500 ECB : {
4382 bruce 501 GIC 4023 : Step *stepa = *((Step **) a);
4382 bruce 502 CBC 4023 : Step *stepb = *((Step **) b);
503 :
4444 heikki.linnakangas 504 GIC 4023 : return strcmp(stepa->name, stepb->name);
505 : }
4444 heikki.linnakangas 506 ECB :
507 : static int
4444 heikki.linnakangas 508 CBC 28145 : step_bsearch_cmp(const void *a, const void *b)
4444 heikki.linnakangas 509 ECB : {
4382 bruce 510 GIC 28145 : char *stepname = (char *) a;
4382 bruce 511 CBC 28145 : Step *step = *((Step **) b);
512 :
4444 heikki.linnakangas 513 GIC 28145 : return strcmp(stepname, step->name);
514 : }
515 :
516 : /*
517 : * Run one permutation
4444 heikki.linnakangas 518 ECB : */
519 : static void
656 tgl 520 GIC 1645 : run_permutation(TestSpec *testspec, int nsteps, PermutationStep **steps)
521 : {
4382 bruce 522 ECB : PGresult *res;
523 : int i;
2614 rhaas 524 GIC 1645 : int nwaiting = 0;
656 tgl 525 ECB : PermutationStep **waiting;
526 :
656 tgl 527 CBC 1645 : waiting = pg_malloc(sizeof(PermutationStep *) * testspec->nsessions);
2614 tgl 528 ECB :
4444 heikki.linnakangas 529 CBC 1645 : printf("\nstarting permutation:");
530 13385 : for (i = 0; i < nsteps; i++)
4444 heikki.linnakangas 531 GIC 11740 : printf(" %s", steps[i]->name);
532 1645 : printf("\n");
4444 heikki.linnakangas 533 ECB :
534 : /* Perform setup */
3869 kgrittn 535 CBC 3301 : for (i = 0; i < testspec->nsetupsqls; i++)
4444 heikki.linnakangas 536 ECB : {
656 tgl 537 GIC 1656 : res = PQexec(conns[0].conn, testspec->setupsqls[i]);
3474 alvherre 538 CBC 1656 : if (PQresultStatus(res) == PGRES_TUPLES_OK)
539 : {
540 56 : printResultSet(res);
541 : }
3474 alvherre 542 GBC 1600 : else if (PQresultStatus(res) != PGRES_COMMAND_OK)
4444 heikki.linnakangas 543 EUB : {
656 tgl 544 UIC 0 : fprintf(stderr, "setup failed: %s", PQerrorMessage(conns[0].conn));
1555 peter 545 LBC 0 : exit(1);
546 : }
4444 heikki.linnakangas 547 GIC 1656 : PQclear(res);
548 : }
4444 heikki.linnakangas 549 ECB :
550 : /* Perform per-session setup */
4444 heikki.linnakangas 551 CBC 5553 : for (i = 0; i < testspec->nsessions; i++)
552 : {
553 3908 : if (testspec->sessions[i]->setupsql)
4444 heikki.linnakangas 554 ECB : {
656 tgl 555 GIC 2513 : res = PQexec(conns[i + 1].conn, testspec->sessions[i]->setupsql);
4252 heikki.linnakangas 556 CBC 2513 : if (PQresultStatus(res) == PGRES_TUPLES_OK)
557 : {
558 26 : printResultSet(res);
559 : }
4252 heikki.linnakangas 560 GBC 2487 : else if (PQresultStatus(res) != PGRES_COMMAND_OK)
4444 heikki.linnakangas 561 EUB : {
4444 heikki.linnakangas 562 UBC 0 : fprintf(stderr, "setup of session %s failed: %s",
656 tgl 563 0 : conns[i + 1].sessionname,
656 tgl 564 UIC 0 : PQerrorMessage(conns[i + 1].conn));
1555 peter 565 LBC 0 : exit(1);
566 : }
4444 heikki.linnakangas 567 GIC 2513 : PQclear(res);
568 : }
569 : }
4444 heikki.linnakangas 570 ECB :
571 : /* Perform steps */
4444 heikki.linnakangas 572 CBC 13385 : for (i = 0; i < nsteps; i++)
4444 heikki.linnakangas 573 ECB : {
656 tgl 574 CBC 11740 : PermutationStep *pstep = steps[i];
575 11740 : Step *step = pstep->step;
656 tgl 576 GIC 11740 : IsoConnInfo *iconn = &conns[1 + step->session];
577 11740 : PGconn *conn = iconn->conn;
578 : bool mustwait;
579 : int j;
580 :
581 : /*
582 : * Check whether the session that needs to perform the next step is
2613 tgl 583 ECB : * still blocked on an earlier step. If so, wait for it to finish.
584 : */
656 tgl 585 GIC 11740 : if (iconn->active_step != NULL)
586 : {
656 tgl 587 ECB : struct timeval start_time;
588 :
656 tgl 589 CBC 33 : gettimeofday(&start_time, NULL);
590 :
591 66 : while (iconn->active_step != NULL)
592 : {
656 tgl 593 GIC 33 : PermutationStep *oldstep = iconn->active_step;
594 :
595 : /*
596 : * Wait for oldstep. But even though we don't use
597 : * STEP_NONBLOCK, it might not complete because of blocker
656 tgl 598 ECB : * conditions.
599 : */
656 tgl 600 GIC 33 : if (!try_complete_step(testspec, oldstep, STEP_RETRY))
601 : {
602 : /* Done, so remove oldstep from the waiting[] array. */
656 tgl 603 ECB : int w;
604 :
656 tgl 605 CBC 46 : for (w = 0; w < nwaiting; w++)
656 tgl 606 ECB : {
656 tgl 607 GIC 46 : if (oldstep == waiting[w])
656 tgl 608 CBC 33 : break;
656 tgl 609 EUB : }
656 tgl 610 CBC 33 : if (w >= nwaiting)
656 tgl 611 UBC 0 : abort(); /* can't happen */
2614 rhaas 612 GBC 33 : if (w + 1 < nwaiting)
2538 tgl 613 LBC 0 : memmove(&waiting[w], &waiting[w + 1],
656 tgl 614 UIC 0 : (nwaiting - (w + 1)) * sizeof(PermutationStep *));
2614 rhaas 615 GIC 33 : nwaiting--;
616 : }
617 :
618 : /*
619 : * Check for other steps that have finished. We should do
620 : * this if oldstep completed, as it might have unblocked
621 : * something. On the other hand, if oldstep hasn't completed,
622 : * we must poll all the active steps in hopes of unblocking
656 tgl 623 ECB : * oldstep. So either way, poll them.
624 : */
656 tgl 625 GIC 33 : nwaiting = try_complete_steps(testspec, waiting, nwaiting,
626 : STEP_NONBLOCK | STEP_RETRY);
627 :
628 : /*
629 : * If the target session is still busy, apply a timeout to
630 : * keep from hanging indefinitely, which could happen with
631 : * incorrect blocker annotations. Use the same 2 *
632 : * max_step_wait limit as try_complete_step does for deciding
633 : * to die. (We don't bother with trying to cancel anything,
656 tgl 634 ECB : * since it's unclear what to cancel in this case.)
635 : */
656 tgl 636 GIC 33 : if (iconn->active_step != NULL)
637 : {
638 : struct timeval current_time;
656 tgl 639 EUB : int64 td;
640 :
656 tgl 641 UBC 0 : gettimeofday(¤t_time, NULL);
642 0 : td = (int64) current_time.tv_sec - (int64) start_time.tv_sec;
643 0 : td *= USECS_PER_SEC;
656 tgl 644 UIC 0 : td += (int64) current_time.tv_usec - (int64) start_time.tv_usec;
656 tgl 645 UBC 0 : if (td > 2 * max_step_wait)
656 tgl 646 EUB : {
656 tgl 647 UBC 0 : fprintf(stderr, "step %s timed out after %d seconds\n",
648 0 : iconn->active_step->name,
649 0 : (int) (td / USECS_PER_SEC));
656 tgl 650 UIC 0 : fprintf(stderr, "active steps are:");
656 tgl 651 UBC 0 : for (j = 1; j < nconns; j++)
652 : {
653 0 : IsoConnInfo *oconn = &conns[j];
656 tgl 654 EUB :
656 tgl 655 UBC 0 : if (oconn->active_step != NULL)
656 tgl 656 UIC 0 : fprintf(stderr, " %s",
656 tgl 657 UBC 0 : oconn->active_step->name);
656 tgl 658 EUB : }
656 tgl 659 UIC 0 : fprintf(stderr, "\n");
660 0 : exit(1);
661 : }
662 : }
663 : }
664 : }
4103 alvherre 665 ECB :
666 : /* Send the query for this step. */
4103 alvherre 667 GBC 11740 : if (!PQsendQuery(conn, step->sql))
668 : {
4185 alvherre 669 UBC 0 : fprintf(stdout, "failed to send query for step %s: %s\n",
670 : step->name, PQerrorMessage(conn));
1555 peter 671 UIC 0 : exit(1);
672 : }
4444 heikki.linnakangas 673 ECB :
674 : /* Remember we launched a step. */
656 tgl 675 GIC 11740 : iconn->active_step = pstep;
4444 heikki.linnakangas 676 ECB :
677 : /* Remember target number of NOTICEs for any blocker conditions. */
656 tgl 678 CBC 11788 : for (j = 0; j < pstep->nblockers; j++)
679 : {
680 48 : PermutationStepBlocker *blocker = pstep->blockers[j];
656 tgl 681 ECB :
656 tgl 682 CBC 48 : if (blocker->blocktype == PSB_NUM_NOTICES)
656 tgl 683 GIC 1 : blocker->target_notices = blocker->num_notices +
684 1 : conns[blocker->step->session + 1].total_notices;
685 : }
2614 rhaas 686 ECB :
687 : /* Try to complete this step without blocking. */
656 tgl 688 GIC 11740 : mustwait = try_complete_step(testspec, pstep, STEP_NONBLOCK);
656 tgl 689 ECB :
690 : /* Check for completion of any steps that were previously waiting. */
656 tgl 691 GIC 11740 : nwaiting = try_complete_steps(testspec, waiting, nwaiting,
692 : STEP_NONBLOCK | STEP_RETRY);
2614 rhaas 693 ECB :
694 : /* If this step is waiting, add it to the array of waiters. */
2614 rhaas 695 GIC 11740 : if (mustwait)
656 tgl 696 652 : waiting[nwaiting++] = pstep;
697 : }
4444 heikki.linnakangas 698 ECB :
2613 tgl 699 : /* Wait for any remaining queries. */
656 tgl 700 GIC 1645 : nwaiting = try_complete_steps(testspec, waiting, nwaiting, STEP_RETRY);
656 tgl 701 GBC 1645 : if (nwaiting != 0)
4212 alvherre 702 EUB : {
656 tgl 703 UIC 0 : fprintf(stderr, "failed to complete permutation due to mutually-blocking steps\n");
704 0 : exit(1);
705 : }
4289 alvherre 706 ECB :
707 : /* Perform per-session teardown */
4444 heikki.linnakangas 708 CBC 5553 : for (i = 0; i < testspec->nsessions; i++)
709 : {
710 3908 : if (testspec->sessions[i]->teardownsql)
4444 heikki.linnakangas 711 ECB : {
656 tgl 712 GIC 202 : res = PQexec(conns[i + 1].conn, testspec->sessions[i]->teardownsql);
3474 alvherre 713 CBC 202 : if (PQresultStatus(res) == PGRES_TUPLES_OK)
714 : {
715 85 : printResultSet(res);
716 : }
3474 alvherre 717 GBC 117 : else if (PQresultStatus(res) != PGRES_COMMAND_OK)
4444 heikki.linnakangas 718 EUB : {
4444 heikki.linnakangas 719 UBC 0 : fprintf(stderr, "teardown of session %s failed: %s",
656 tgl 720 UIC 0 : conns[i + 1].sessionname,
721 0 : PQerrorMessage(conns[i + 1].conn));
4444 heikki.linnakangas 722 ECB : /* don't exit on teardown failure */
723 : }
4444 heikki.linnakangas 724 GIC 202 : PQclear(res);
725 : }
726 : }
4444 heikki.linnakangas 727 ECB :
728 : /* Perform teardown */
4444 heikki.linnakangas 729 CBC 1645 : if (testspec->teardownsql)
4444 heikki.linnakangas 730 ECB : {
656 tgl 731 GIC 1593 : res = PQexec(conns[0].conn, testspec->teardownsql);
4252 heikki.linnakangas 732 CBC 1593 : if (PQresultStatus(res) == PGRES_TUPLES_OK)
733 : {
734 39 : printResultSet(res);
735 : }
4252 heikki.linnakangas 736 GBC 1554 : else if (PQresultStatus(res) != PGRES_COMMAND_OK)
4444 heikki.linnakangas 737 EUB : {
4444 heikki.linnakangas 738 UIC 0 : fprintf(stderr, "teardown failed: %s",
656 tgl 739 0 : PQerrorMessage(conns[0].conn));
4444 heikki.linnakangas 740 ECB : /* don't exit on teardown failure */
741 : }
4444 heikki.linnakangas 742 GIC 1593 : PQclear(res);
4444 heikki.linnakangas 743 ECB : }
2614 tgl 744 :
2614 tgl 745 GIC 1645 : free(waiting);
656 746 1645 : }
747 :
748 : /*
749 : * Check for completion of any waiting step(s).
750 : * Remove completed ones from the waiting[] array,
751 : * and return the new value of nwaiting.
752 : * See try_complete_step for the meaning of the flags.
656 tgl 753 ECB : */
754 : static int
656 tgl 755 GIC 13418 : try_complete_steps(TestSpec *testspec, PermutationStep **waiting,
756 : int nwaiting, int flags)
757 : {
758 : int old_nwaiting;
759 : bool have_blocker;
760 :
656 tgl 761 ECB : do
762 : {
656 tgl 763 GIC 13422 : int w = 0;
656 tgl 764 ECB :
765 : /* Reset latch; we only care about notices received within loop. */
656 tgl 766 GIC 13422 : any_new_notice = false;
656 tgl 767 ECB :
768 : /* Likewise, these variables reset for each retry. */
656 tgl 769 GIC 13422 : old_nwaiting = nwaiting;
770 13422 : have_blocker = false;
656 tgl 771 ECB :
772 : /* Scan the array, try to complete steps. */
656 tgl 773 CBC 14523 : while (w < nwaiting)
774 : {
656 tgl 775 GIC 1101 : if (try_complete_step(testspec, waiting[w], flags))
656 tgl 776 ECB : {
777 : /* Still blocked, leave it alone. */
656 tgl 778 CBC 482 : if (waiting[w]->nblockers > 0)
656 tgl 779 GIC 20 : have_blocker = true;
780 482 : w++;
781 : }
782 : else
656 tgl 783 ECB : {
784 : /* Done, remove it from array. */
656 tgl 785 CBC 619 : if (w + 1 < nwaiting)
786 21 : memmove(&waiting[w], &waiting[w + 1],
656 tgl 787 GIC 21 : (nwaiting - (w + 1)) * sizeof(PermutationStep *));
788 619 : nwaiting--;
789 : }
790 : }
791 :
792 : /*
793 : * If any of the still-waiting steps have blocker conditions attached,
794 : * it's possible that one of the steps we examined afterwards has
795 : * released them (either by completing, or by sending a NOTICE). If
796 : * any step completions or NOTICEs happened, repeat the loop until
797 : * none occurs. Without this provision, completion timing could vary
656 tgl 798 ECB : * depending on the order in which the steps appear in the array.
799 : */
656 tgl 800 GIC 13422 : } while (have_blocker && (nwaiting < old_nwaiting || any_new_notice));
801 13418 : return nwaiting;
802 : }
803 :
804 : /*
805 : * Our caller already sent the query associated with this step. Wait for it
806 : * to either complete, or hit a blocking condition.
807 : *
808 : * When calling this function on behalf of a given step for a second or later
809 : * time, pass the STEP_RETRY flag. Do not pass it on the first call.
810 : *
811 : * Returns true if the step was *not* completed, false if it was completed.
812 : * Reasons for non-completion are (a) the STEP_NONBLOCK flag was specified
813 : * and the query is waiting to acquire a lock, or (b) the step has an
814 : * unsatisfied blocker condition. When STEP_NONBLOCK is given, we assume
815 : * that any lock wait will persist until we have executed additional steps.
4289 alvherre 816 ECB : */
817 : static bool
656 tgl 818 CBC 12874 : try_complete_step(TestSpec *testspec, PermutationStep *pstep, int flags)
4289 alvherre 819 ECB : {
656 tgl 820 CBC 12874 : Step *step = pstep->step;
656 tgl 821 GIC 12874 : IsoConnInfo *iconn = &conns[1 + step->session];
822 12874 : PGconn *conn = iconn->conn;
823 : fd_set read_set;
2614 rhaas 824 ECB : struct timeval start_time;
825 : struct timeval timeout;
4289 alvherre 826 GIC 12874 : int sock = PQsocket(conn);
827 : int ret;
4289 alvherre 828 ECB : PGresult *res;
829 : PGnotify *notify;
2614 rhaas 830 GIC 12874 : bool canceled = false;
831 :
832 : /*
833 : * If the step is annotated with (*), then on the first call, force it to
834 : * wait. This is useful for ensuring consistent output when the step
656 tgl 835 ECB : * might or might not complete so fast that we don't observe it waiting.
836 : */
656 tgl 837 GIC 12874 : if (!(flags & STEP_RETRY))
838 : {
656 tgl 839 ECB : int i;
840 :
656 tgl 841 CBC 11777 : for (i = 0; i < pstep->nblockers; i++)
842 : {
843 48 : PermutationStepBlocker *blocker = pstep->blockers[i];
844 :
845 48 : if (blocker->blocktype == PSB_ONCE)
846 : {
847 11 : printf("step %s: %s <waiting ...>\n",
848 : step->name, step->sql);
656 tgl 849 GIC 11 : return true;
850 : }
851 : }
656 tgl 852 ECB : }
853 :
2588 peter_e 854 GBC 12863 : if (sock < 0)
2588 peter_e 855 EUB : {
2588 peter_e 856 UIC 0 : fprintf(stderr, "invalid socket: %s", PQerrorMessage(conn));
1555 peter 857 0 : exit(1);
2588 peter_e 858 ECB : }
859 :
2614 rhaas 860 GIC 12863 : gettimeofday(&start_time, NULL);
4289 alvherre 861 CBC 218671 : FD_ZERO(&read_set);
862 :
2614 rhaas 863 27058 : while (PQisBusy(conn))
4289 alvherre 864 ECB : {
4289 alvherre 865 CBC 15286 : FD_SET(sock, &read_set);
4289 alvherre 866 GIC 15286 : timeout.tv_sec = 0;
4289 alvherre 867 CBC 15286 : timeout.tv_usec = 10000; /* Check for lock waits every 10ms. */
4289 alvherre 868 ECB :
4289 alvherre 869 GIC 15286 : ret = select(sock + 1, &read_set, NULL, NULL, &timeout);
3955 bruce 870 GBC 15286 : if (ret < 0) /* error in select() */
4289 alvherre 871 EUB : {
3655 tgl 872 UBC 0 : if (errno == EINTR)
873 0 : continue;
4289 alvherre 874 UIC 0 : fprintf(stderr, "select failed: %s\n", strerror(errno));
1555 peter 875 LBC 0 : exit(1);
876 : }
3955 bruce 877 GIC 15286 : else if (ret == 0) /* select() timeout: check for lock wait */
878 : {
879 : struct timeval current_time;
880 : int64 td;
4289 alvherre 881 ECB :
882 : /* If it's OK for the step to block, check whether it has. */
2614 rhaas 883 GIC 3200 : if (flags & STEP_NONBLOCK)
884 : {
2603 tgl 885 ECB : bool waiting;
2614 rhaas 886 :
656 tgl 887 GIC 3192 : res = PQexecPrepared(conns[0].conn, PREP_WAITING, 1,
656 tgl 888 CBC 3192 : &conns[step->session + 1].backend_pid_str,
2614 rhaas 889 ECB : NULL, NULL, 0);
2603 tgl 890 GIC 6384 : if (PQresultStatus(res) != PGRES_TUPLES_OK ||
2603 tgl 891 GBC 3192 : PQntuples(res) != 1)
2614 rhaas 892 EUB : {
2614 rhaas 893 UBC 0 : fprintf(stderr, "lock wait query failed: %s",
656 tgl 894 UIC 0 : PQerrorMessage(conns[0].conn));
1555 peter 895 LBC 0 : exit(1);
2614 rhaas 896 ECB : }
2603 tgl 897 GIC 3192 : waiting = ((PQgetvalue(res, 0, 0))[0] == 't');
2614 rhaas 898 CBC 3192 : PQclear(res);
899 :
2603 tgl 900 GIC 3192 : if (waiting) /* waiting to acquire a lock */
901 : {
902 : /*
903 : * Since it takes time to perform the lock-check query,
904 : * some data --- notably, NOTICE messages --- might have
905 : * arrived since we looked. We must call PQconsumeInput
906 : * and then PQisBusy to collect and process any such
907 : * messages. In the (unlikely) case that PQisBusy then
908 : * returns false, we might as well go examine the
1352 tgl 909 ECB : * available result.
910 : */
1352 tgl 911 GBC 1091 : if (!PQconsumeInput(conn))
912 : {
1352 tgl 913 UBC 0 : fprintf(stderr, "PQconsumeInput failed: %s\n",
914 : PQerrorMessage(conn));
1352 tgl 915 LBC 0 : exit(1);
1352 tgl 916 EUB : }
1352 tgl 917 GIC 1091 : if (!PQisBusy(conn))
1352 tgl 918 UIC 0 : break;
919 :
920 : /*
921 : * conn is still busy, so conclude that the step really is
1352 tgl 922 ECB : * waiting.
923 : */
2613 tgl 924 GIC 1091 : if (!(flags & STEP_RETRY))
2613 tgl 925 CBC 610 : printf("step %s: %s <waiting ...>\n",
926 : step->name, step->sql);
2614 rhaas 927 GIC 1091 : return true;
928 : }
929 : /* else, not waiting */
930 : }
4289 alvherre 931 ECB :
2614 rhaas 932 : /* Figure out how long we've been waiting for this step. */
2614 rhaas 933 CBC 2109 : gettimeofday(¤t_time, NULL);
934 2109 : td = (int64) current_time.tv_sec - (int64) start_time.tv_sec;
2614 rhaas 935 GIC 2109 : td *= USECS_PER_SEC;
936 2109 : td += (int64) current_time.tv_usec - (int64) start_time.tv_usec;
937 :
938 : /*
939 : * After max_step_wait microseconds, try to cancel the query.
940 : *
941 : * If the user tries to test an invalid permutation, we don't want
942 : * to hang forever, especially when this is running in the
943 : * buildfarm. This will presumably lead to this permutation
944 : * failing, but remaining permutations and tests should still be
1581 noah 945 ECB : * OK.
946 : */
1217 tgl 947 GBC 2109 : if (td > max_step_wait && !canceled)
948 : {
2613 tgl 949 UBC 0 : PGcancel *cancel = PQgetCancel(conn);
950 :
2614 rhaas 951 UIC 0 : if (cancel != NULL)
952 : {
2613 tgl 953 EUB : char buf[256];
954 :
2614 tgl 955 UIC 0 : if (PQcancel(cancel, buf, sizeof(buf)))
956 : {
957 : /*
958 : * print to stdout not stderr, as this should appear
1217 tgl 959 EUB : * in the test case's results
960 : */
1217 tgl 961 UBC 0 : printf("isolationtester: canceling step %s after %d seconds\n",
962 : step->name, (int) (td / USECS_PER_SEC));
2614 tgl 963 UIC 0 : canceled = true;
1217 tgl 964 EUB : }
2614 965 : else
2614 tgl 966 UIC 0 : fprintf(stderr, "PQcancel failed: %s\n", buf);
rhaas 967 0 : PQfreeCancel(cancel);
968 : }
969 : }
970 :
971 : /*
972 : * After twice max_step_wait, just give up and die.
973 : *
974 : * Since cleanup steps won't be run in this case, this may cause
975 : * later tests to fail. That stinks, but it's better than waiting
2614 rhaas 976 ECB : * forever for the server to respond to the cancel.
977 : */
1217 tgl 978 GBC 2109 : if (td > 2 * max_step_wait)
2614 rhaas 979 EUB : {
1217 tgl 980 UBC 0 : fprintf(stderr, "step %s timed out after %d seconds\n",
1217 tgl 981 UIC 0 : step->name, (int) (td / USECS_PER_SEC));
1555 peter 982 0 : exit(1);
4289 alvherre 983 ECB : }
984 : }
4289 alvherre 985 GBC 12086 : else if (!PQconsumeInput(conn)) /* select(): data available */
986 : {
4089 tgl 987 UBC 0 : fprintf(stderr, "PQconsumeInput failed: %s\n",
988 : PQerrorMessage(conn));
1555 peter 989 UIC 0 : exit(1);
990 : }
991 : }
992 :
993 : /*
994 : * The step is done, but we won't report it as complete so long as there
656 tgl 995 ECB : * are blockers.
996 : */
656 tgl 997 CBC 11772 : if (step_has_blocker(pstep))
656 tgl 998 ECB : {
656 tgl 999 GIC 32 : if (!(flags & STEP_RETRY))
656 tgl 1000 CBC 31 : printf("step %s: %s <waiting ...>\n",
1001 : step->name, step->sql);
656 tgl 1002 GIC 32 : return true;
1003 : }
656 tgl 1004 ECB :
1005 : /* Otherwise, go ahead and complete it. */
4289 alvherre 1006 GIC 11740 : if (flags & STEP_RETRY)
4289 alvherre 1007 CBC 652 : printf("step %s: <... completed>\n", step->name);
1008 : else
1009 11088 : printf("step %s: %s\n", step->name, step->sql);
1010 :
1011 23746 : while ((res = PQgetResult(conn)))
1012 : {
1013 12006 : switch (PQresultStatus(res))
1014 : {
1015 8148 : case PGRES_COMMAND_OK:
656 tgl 1016 ECB : case PGRES_EMPTY_QUERY:
4289 alvherre 1017 CBC 8148 : break;
1018 3386 : case PGRES_TUPLES_OK:
1019 3386 : printResultSet(res);
4289 alvherre 1020 GIC 3386 : break;
1021 472 : case PGRES_FATAL_ERROR:
1022 :
1023 : /*
1024 : * Detail may contain XID values, so we want to just show
1025 : * primary. Beware however that libpq-generated error results
1026 : * may not contain subfields, only an old-style message.
3659 tgl 1027 ECB : */
1028 : {
3659 tgl 1029 CBC 472 : const char *sev = PQresultErrorField(res,
1030 : PG_DIAG_SEVERITY);
3659 tgl 1031 GIC 472 : const char *msg = PQresultErrorField(res,
2118 tgl 1032 ECB : PG_DIAG_MESSAGE_PRIMARY);
3659 1033 :
3659 tgl 1034 GIC 472 : if (sev && msg)
656 tgl 1035 CBC 470 : printf("%s: %s\n", sev, msg);
1036 : else
1037 2 : printf("%s\n", PQresultErrorMessage(res));
3659 tgl 1038 EUB : }
4289 alvherre 1039 GBC 472 : break;
4289 alvherre 1040 UIC 0 : default:
1041 0 : printf("unexpected result status: %s\n",
4289 alvherre 1042 ECB : PQresStatus(PQresultStatus(res)));
1043 : }
4289 alvherre 1044 GIC 12006 : PQclear(res);
1045 : }
4289 alvherre 1046 ECB :
1351 tgl 1047 : /* Report any available NOTIFY messages, too */
1351 tgl 1048 GIC 11740 : PQconsumeInput(conn);
1049 11767 : while ((notify = PQnotifies(conn)) != NULL)
1351 tgl 1050 ECB : {
1051 : /* Try to identify which session it came from */
1351 tgl 1052 GIC 27 : const char *sendername = NULL;
1053 : char pidstring[32];
656 tgl 1054 ECB : int i;
1055 :
656 tgl 1056 CBC 27 : for (i = 0; i < testspec->nsessions; i++)
1057 : {
1058 27 : if (notify->be_pid == conns[i + 1].backend_pid)
1351 tgl 1059 ECB : {
656 tgl 1060 GIC 27 : sendername = conns[i + 1].sessionname;
1351 1061 27 : break;
1351 tgl 1062 ECB : }
1063 : }
1351 tgl 1064 GIC 27 : if (sendername == NULL)
1351 tgl 1065 EUB : {
1066 : /* Doesn't seem to be any test session, so show the hard way */
1351 tgl 1067 UIC 0 : snprintf(pidstring, sizeof(pidstring), "PID %d", notify->be_pid);
1351 tgl 1068 LBC 0 : sendername = pidstring;
1069 : }
1351 tgl 1070 GIC 27 : printf("%s: NOTIFY \"%s\" with payload \"%s\" from %s\n",
1351 tgl 1071 ECB : testspec->sessions[step->session]->name,
1072 : notify->relname, notify->extra, sendername);
1351 tgl 1073 GIC 27 : PQfreemem(notify);
1074 27 : PQconsumeInput(conn);
1075 : }
1351 tgl 1076 ECB :
1077 : /* Connection is now idle. */
656 tgl 1078 CBC 11740 : iconn->active_step = NULL;
1079 :
656 tgl 1080 GIC 11740 : return false;
1081 : }
1082 :
656 tgl 1083 ECB : /* Detect whether a step has any unsatisfied blocker conditions */
1084 : static bool
656 tgl 1085 GIC 11772 : step_has_blocker(PermutationStep *pstep)
1086 : {
656 tgl 1087 ECB : int i;
1088 :
656 tgl 1089 CBC 11820 : for (i = 0; i < pstep->nblockers; i++)
1090 : {
656 tgl 1091 GIC 80 : PermutationStepBlocker *blocker = pstep->blockers[i];
656 tgl 1092 ECB : IsoConnInfo *iconn;
1093 :
656 tgl 1094 CBC 80 : switch (blocker->blocktype)
1095 : {
1096 11 : case PSB_ONCE:
656 tgl 1097 ECB : /* Ignore; try_complete_step handles this specially */
656 tgl 1098 GIC 11 : break;
656 tgl 1099 CBC 68 : case PSB_OTHER_STEP:
656 tgl 1100 ECB : /* Block if referenced step is active */
656 tgl 1101 CBC 68 : iconn = &conns[1 + blocker->step->session];
1102 68 : if (iconn->active_step &&
1103 32 : iconn->active_step->step == blocker->step)
1104 32 : return true;
656 tgl 1105 GIC 36 : break;
656 tgl 1106 CBC 1 : case PSB_NUM_NOTICES:
656 tgl 1107 ECB : /* Block if not enough notices received yet */
656 tgl 1108 GBC 1 : iconn = &conns[1 + blocker->step->session];
656 tgl 1109 CBC 1 : if (iconn->total_notices < blocker->target_notices)
656 tgl 1110 UIC 0 : return true;
656 tgl 1111 GIC 1 : break;
656 tgl 1112 ECB : }
1113 : }
4289 alvherre 1114 GIC 11740 : return false;
1115 : }
4289 alvherre 1116 ECB :
1117 : static void
4444 heikki.linnakangas 1118 GIC 3592 : printResultSet(PGresult *res)
1119 : {
655 tgl 1120 ECB : PQprintOpt popt;
4382 bruce 1121 :
655 tgl 1122 CBC 3592 : memset(&popt, 0, sizeof(popt));
1123 3592 : popt.header = true;
1124 3592 : popt.align = true;
1125 3592 : popt.fieldSep = "|";
655 tgl 1126 GIC 3592 : PQprint(stdout, res, &popt);
4444 heikki.linnakangas 1127 3592 : }
1128 :
656 tgl 1129 ECB : /* notice processor for regular user sessions */
1130 : static void
1612 alvherre 1131 CBC 544 : isotesterNoticeProcessor(void *arg, const char *message)
1132 : {
656 tgl 1133 GIC 544 : IsoConnInfo *myconn = (IsoConnInfo *) arg;
656 tgl 1134 ECB :
1135 : /* Prefix the backend's message with the session name. */
656 tgl 1136 CBC 544 : printf("%s: %s", myconn->sessionname, message);
656 tgl 1137 ECB : /* Record notices, since we may need this to decide to unblock a step. */
656 tgl 1138 CBC 544 : myconn->total_notices++;
656 tgl 1139 GIC 544 : any_new_notice = true;
1612 alvherre 1140 544 : }
1141 :
1612 alvherre 1142 ECB : /* notice processor, hides the message */
1143 : static void
1612 alvherre 1144 GIC 434 : blackholeNoticeProcessor(void *arg, const char *message)
1612 alvherre 1145 ECB : {
1146 : /* do nothing */
1612 alvherre 1147 GIC 434 : }
|