diff --git a/docs/ref/pgaftest.rst b/docs/ref/pgaftest.rst index 6c543cc65..166fa0fb8 100644 --- a/docs/ref/pgaftest.rst +++ b/docs/ref/pgaftest.rst @@ -10,26 +10,213 @@ spins up the cluster using Docker Compose, and drives the steps to completion. Two modes of operation are supported: - **CI mode** (``pgaftest run``): headless TAP output, non-zero exit on failure. -- **Interactive mode** (``pgaftest setup``): cluster stays up, shell or tmux - session opened for hands-on exploration. +- **Interactive mode** (``pgaftest cluster setup`` / ``pgaftest tmux``): cluster + stays up, shell or tmux session opened for hands-on exploration. .. contents:: :local: :depth: 2 +Host commands vs. container commands +-------------------------------------- + +``pgaftest`` commands fall into two groups depending on where they must be +run. + +**Host commands** orchestrate Docker Compose itself — they generate YAML, +bring stacks up and down, or operate on local spec files. Run these on the +machine that owns the Docker socket (developer workstation or CI runner). + +**Container commands** operate against an already-running stack from inside +the ``pgaftest`` service container, which has the Docker CLI and the host +Docker socket bind-mounted (Docker-out-of-Docker, DooD). These are the +commands you type in the interactive shell that ``pgaftest tmux`` drops you +into. + +.. list-table:: + :header-rows: 1 + :widths: 40 12 48 + + * - Command + - Where + - Purpose + * - ``pgaftest run `` + - **Host** + - CI mode: full lifecycle — up, setup, sequence, teardown, down. + Emits TAP to stdout. + * - ``pgaftest cluster setup `` + - **Host** + - Generate compose YAML, bring the stack up, run ``setup{}``, then + return control for interactive use. + * - ``pgaftest tmux `` + - **Host** + - Same as ``cluster setup`` but launches a tmux session: top pane + ``pg_autoctl watch``, bottom pane interactive shell in the + ``pgaftest`` container. + * - ``pgaftest cluster prepare []`` + - **Host** + - Write compose YAML and ``.ini`` files to a directory without + starting anything. Useful for inspecting generated config. + * - ``pgaftest cluster down `` + - **Host** + - Run the ``teardown{}`` block then ``docker compose down --volumes``. + * - ``pgaftest show compose `` + - **Host** + - Dry-run: render the generated ``docker-compose.yml`` to stdout + without starting anything. + * - ``pgaftest show spec `` + - **Host** + - Print the spec file source. + * - ``pgaftest indent `` + - **Host** + - Parse and rewrite the spec with canonical indentation in place. + * - ``pgaftest help`` + - **Host** + - Print the full command tree. + * - ``pgaftest step []`` + - **Container** + - Run the next pending step (auto-advance) or a specific named step + against the live stack. Records progress in a state file so + repeated bare ``pgaftest step`` calls walk the sequence forward, + retrying a failed step before advancing. + * - ``pgaftest show steps`` + - **Container** + - List the sequence steps with progress markers: ``*`` = next to run, + ``!`` = last failed (will retry on next ``pgaftest step``), space + prefix = completed. + * - ``pgaftest show step`` + - **Container** + - Print the DSL commands that will run when ``pgaftest step`` is called + next, so you can review what is about to happen. + * - ``pgaftest show state`` + - **Container** + - Print a ``Step X/N: name`` progress header followed by + ``pg_autoctl show state`` output for the whole formation. + * - ``pgaftest sql { }`` + - **Container** + - Run a SQL query on a named node and print the result to stdout. + * - ``pgaftest network disconnect `` + - **Container** + - Disconnect a node from its Compose network, simulating a network + partition. + * - ``pgaftest network connect `` + - **Container** + - Reconnect a previously disconnected node. + * - ``pgaftest cluster down`` + - **Container** + - Run ``teardown{}`` and ``docker compose down`` via DooD from inside + the container. + + +Typical interactive session +---------------------------- + +Start the cluster on the host and drop into a tmux session:: + + pgaftest tmux tests/tap/specs/basic_failover.pgaf + +``pg_autoctl watch`` fills the top pane. The bottom pane is an interactive +shell inside the ``pgaftest`` service container. From there:: + + # See which steps are available and where you are + pgaftest show steps + + # Preview what the next step will do + pgaftest show step + + # Check cluster state + pgaftest show state + + # Run the next step (auto-advance) + pgaftest step + + # Or run a specific step by name + pgaftest step stop_primary + + # Inject a network partition manually + pgaftest network disconnect node1 + + # Check the cluster reacted correctly + pgaftest show state + + # Restore the network and continue + pgaftest network connect node1 + pgaftest step + + # Tear down when done + pgaftest cluster down + +The ``pg_autoctl watch`` output in the top tmux pane updates in real time +throughout this session. + + +Docker-out-of-Docker (DooD) architecture +----------------------------------------- + +``pgaftest cluster setup`` and ``pgaftest tmux`` generate a Compose file that +includes a ``pgaftest`` service alongside the cluster nodes. That service: + +* runs as the ``docker`` user whose ``$HOME`` is ``/var/lib/postgres``; +* sets ``working_dir: /var/lib/postgres`` so the interactive shell lands in + the user's home directory; +* mounts the spec file at ``~/spec.pgaf`` (``/var/lib/postgres/spec.pgaf``); +* bind-mounts the host Docker socket (``/var/run/docker.sock``) so that + ``docker compose exec`` calls issued from inside the container target the + host's Docker daemon and reach the sibling cluster containers; +* pre-sets ``PGAFTEST_SPEC``, ``PGAFTEST_HOST_WORK_DIR``, and + ``PGAFTEST_IN_CONTAINER=1`` in its environment so all container commands + discover the spec file and Compose project without extra arguments, and so + the binary knows it is running inside the container (used to pick the + correct state-file location). + +In ``tmux`` mode the service runs ``sleep infinity`` to stay alive. +In CI mode (``pgaftest run``) it runs ``pgaftest run ~/spec.pgaf`` directly. + + +Step state file +--------------- + +Container commands record progress in ``~/pgaftest.state`` +(``$HOME/pgaftest.state`` inside the pgaftest container), a small JSON file +that tracks: + +* ``current`` — index of the next step to run in the sequence; +* ``last_step`` — name of the most recently executed step; +* ``last_ok`` — whether that step succeeded. + +On success ``current`` advances; on failure it stays pointing at the failed +step so the next bare ``pgaftest step`` retries it rather than skipping +ahead. + +The file lives in the container user's home directory (``/var/lib/postgres`` +for the ``docker`` user) rather than in the host-side bind-mounted work +directory, so it is always writable regardless of how the bind-mount +ownership maps between host and container. It persists for the lifetime of +the container. + +When ``pgaftest step`` is run on the host (outside the container), the state +file is written to ``$TMPDIR/pgaftest//pgaftest.state`` alongside +the generated compose files. + + Synopsis -------- :: - pgaftest run [options] - pgaftest run --schedule [options] - pgaftest setup [options] [--tmux] - pgaftest step [--work-dir ] - pgaftest show - pgaftest prepare [] - pgaftest down [--work-dir ] + pgaftest run [options] + pgaftest run --schedule [options] + pgaftest tmux [options] + pgaftest cluster setup [options] + pgaftest cluster prepare [] + pgaftest cluster down [] [--work-dir ] + pgaftest step [] [--work-dir ] + pgaftest show compose|spec|steps|step|state [] + pgaftest sql { } + pgaftest network disconnect|connect + pgaftest indent + pgaftest help Sub-commands @@ -62,91 +249,109 @@ Options: ``--no-cleanup`` Leave the compose stack running after the run for post-mortem inspection. - Use ``pgaftest down`` to clean up manually. - -.. _pgaftest_setup: + Use ``pgaftest cluster down`` to clean up manually. -``pgaftest setup`` -~~~~~~~~~~~~~~~~~~ +.. _pgaftest_tmux: -Start a cluster interactively. Docker Compose is started and the -``setup {}`` block runs. Control is then handed back to you. +``pgaftest tmux`` +~~~~~~~~~~~~~~~~~ -:: +Generate compose YAML, bring the stack up, run ``setup {}``, then launch a +tmux session for interactive exploration:: - pgaftest setup tests/tap/specs/basic_operation.pgaf - pgaftest setup docs/tutorial/interactive_tutorial.pgaf --tmux + pgaftest tmux tests/tap/specs/basic_operation.pgaf -Options: +The session has two panes: -``--tmux`` - Open a three-pane tmux session immediately after the cluster is ready. - The setup block runs in the bottom pane so you can watch the logs pane - while the cluster initialises. The three panes are: +- **top** — ``pg_autoctl watch`` on the monitor (live FSM state table) +- **bottom** — interactive shell in the ``pgaftest`` service container - - **top** — ``docker compose logs -f`` (live container output) - - **middle** — ``pg_autoctl watch`` on the monitor - - **bottom** — interactive ``bash`` in the first data node (once setup - completes) +Options: ``--work-dir `` Working directory (default: ``$TMPDIR/pgaftest/``). -.. _pgaftest_step: +.. _pgaftest_cluster: -``pgaftest step`` -~~~~~~~~~~~~~~~~~ +``pgaftest cluster`` +~~~~~~~~~~~~~~~~~~~~ -Run a single named step against a cluster that was started with -``pgaftest setup``. +Sub-commands for managing the Docker Compose stack lifecycle. -:: +``pgaftest cluster setup [options] `` + Generate compose YAML, bring the stack up, run ``setup {}``, then return + control for interactive use (no tmux window). Use ``pgaftest tmux`` for + the tmux variant. + + Options: + + ``--work-dir `` + Working directory (default: ``$TMPDIR/pgaftest/``). + +``pgaftest cluster prepare []`` + Write ``docker-compose.yml``, per-node ``.ini`` files, and a ``Makefile`` + to an output directory for manual inspection or customisation without + starting anything:: - pgaftest step stop_primary --work-dir /tmp/pgaftest/basic_operation + pgaftest cluster prepare tests/tap/specs/basic_operation.pgaf ./my-cluster -The step name must match a ``step {}`` block in the spec. The spec -file is read from ``/spec.pgaf``. +``pgaftest cluster down [] [--work-dir ]`` + Run the ``teardown {}`` block (if any) and then ``docker compose down + --volumes --remove-orphans``:: -.. _pgaftest_down: + pgaftest cluster down tests/tap/specs/basic_operation.pgaf + pgaftest cluster down --work-dir /tmp/pgaftest/basic_operation -``pgaftest down`` +.. _pgaftest_step: + +``pgaftest step`` ~~~~~~~~~~~~~~~~~ -Run the ``teardown {}`` block (if any) and then ``docker compose down ---volumes --remove-orphans``. +Run a step against a live cluster (container command):: -:: + # Run the next pending step (auto-advance using the state file) + pgaftest step + + # Run a specific step by name + pgaftest step stop_primary - pgaftest down --work-dir /tmp/pgaftest/basic_operation - pgaftest down tests/tap/specs/basic_operation.pgaf +When called without a step name, ``pgaftest step`` reads the state file to +find the next step to run, or retries the last step if it failed. On success +the cursor advances; on failure it stays so the next invocation retries. -When called with only ``--work-dir``, the project name is derived from the -last path component of the working directory, matching the name that -``pgaftest setup`` used when creating the stack. +Inside the ``pgaftest`` container the spec file and work directory are +resolved automatically from the ``PGAFTEST_SPEC`` and +``PGAFTEST_HOST_WORK_DIR`` environment variables. .. _pgaftest_show: ``pgaftest show`` ~~~~~~~~~~~~~~~~~ -Print the ``docker-compose.yml`` that would be generated from the spec, -without running anything. +Sub-commands for inspecting a spec or a running session: -:: - - pgaftest show tests/tap/specs/basic_operation.pgaf +``pgaftest show compose []`` + Render the generated ``docker-compose.yml`` to stdout without starting + anything. -.. _pgaftest_prepare: +``pgaftest show spec []`` + Print the spec file source. -``pgaftest prepare`` -~~~~~~~~~~~~~~~~~~~~ +``pgaftest show steps []`` + List all steps in the sequence with progress markers (container command):: -Write ``docker-compose.yml``, per-node ``.ini`` files, and a ``Makefile`` -to an output directory for manual inspection or customisation. + * test_001_verify_sync_replication ← next to run + test_002_cut_replication_link ← completed + ! test_003_primary_becomes_wait_primary ← failed, will retry -:: +``pgaftest show step []`` + Print the DSL commands that will run on the next ``pgaftest step`` + invocation, so you can review what is about to happen (container command). - pgaftest prepare tests/tap/specs/basic_operation.pgaf ./my-cluster +``pgaftest show state []`` + Print a ``Step X/N: name`` progress header followed by + ``pg_autoctl show state`` output for the whole formation (container + command). Spec file format @@ -234,9 +439,6 @@ Commands inside ``setup``, ``teardown``, and ``step`` blocks wait until primary, secondary [timeout s] wait until stopped [timeout s] -The multi-node form ``wait until primary, secondary`` waits until at least -one node in each named state is present in the formation. - **Assertions** .. code-block:: text @@ -262,9 +464,6 @@ one node in each named state is present in the formation. expect { } expect error [] -``expect`` matches the output of the immediately preceding ``sql`` command. -Fields are separated by whitespace; rows are wrapped in ``{ }``. - **Network** .. code-block:: text @@ -322,19 +521,23 @@ Environment variables PGAF_IMAGE=pgaf:run pgaftest run tests/tap/specs/basic_operation.pgaf -``PGAFTEST_COMPOSE_SERVICE`` - Name of the service inside which ``pgaftest`` itself runs when executing - inside a container. Used by the CI workflow to locate the binary. +``PGAFTEST_SPEC`` + Path to the spec file inside the container. Set automatically by + ``pgaftest setup`` in the generated Compose environment; allows all + container commands to find the spec without an explicit argument. + +``PGAFTEST_IN_CONTAINER`` + Set to ``"1"`` inside the pgaftest service container. Used to detect + whether the binary is running in the container vs. the host. ``PGAFTEST_HOST_WORK_DIR`` - Host-side working directory when ``pgaftest`` runs inside a container. - Bind-mounted so compose files written by the binary are visible to the - Docker daemon on the host. + Host-side working directory, set automatically in the container + environment. Container commands write ``pgaftest.state`` here so + progress persists across ``docker compose exec`` invocations. ``TMPDIR`` - Base directory for auto-derived working directories - (default: ``/tmp``). Working directories are placed under - ``$TMPDIR/pgaftest/``. + Base directory for auto-derived working directories (default: ``/tmp``). + Working directories are placed under ``$TMPDIR/pgaftest/``. TAP output @@ -358,34 +561,6 @@ On failure:: __ https://testanything.org/tap-version-13-specification.html -Examples --------- - -**Run a single spec**:: - - pgaftest run tests/tap/specs/basic_operation.pgaf - -**Run the full schedule**:: - - pgaftest run --schedule tests/tap/schedule - -**Bring up an interactive cluster, watch it in tmux**:: - - pgaftest setup docs/tutorial/interactive_tutorial.pgaf --tmux - -**Run a named step against a live cluster**:: - - pgaftest step stop_primary --work-dir /tmp/pgaftest/basic_operation - -**Tear down a cluster started with** ``--no-cleanup`` **or** ``setup``:: - - pgaftest down --work-dir /tmp/pgaftest/basic_operation - -**Print the generated docker-compose.yml without running anything**:: - - pgaftest show tests/tap/specs/basic_operation.pgaf - - See also -------- diff --git a/src/bin/Makefile b/src/bin/Makefile index fcdca4ae7..734eb561f 100644 --- a/src/bin/Makefile +++ b/src/bin/Makefile @@ -1,15 +1,21 @@ # Copyright (c) Microsoft Corporation. All rights reserved. # Licensed under the PostgreSQL License. -all: common pg_autoctl pgaftest ; +COMMON_LIB = common/libpgaf_common.a -common: +all: pg_autoctl pgaftest ; + +# Build the shared archive once, serially, before the two binaries run in +# parallel. Both pg_autoctl and pgaftest include Makefile.common which +# defines compile rules for common/*.c; without this serialisation a +# parallel make -j would race to write the same .o files simultaneously. +$(COMMON_LIB): $(MAKE) -C common -pg_autoctl: common +pg_autoctl: $(COMMON_LIB) $(MAKE) -C pg_autoctl pg_autoctl -pgaftest: common +pgaftest: $(COMMON_LIB) $(MAKE) -C pgaftest pgaftest clean: @@ -21,4 +27,4 @@ install: pg_autoctl pgaftest $(MAKE) -C pg_autoctl install $(MAKE) -C pgaftest install -.PHONY: all common pg_autoctl pgaftest install clean +.PHONY: all pg_autoctl pgaftest install clean diff --git a/src/bin/common/Makefile.common b/src/bin/common/Makefile.common index 8d527d144..8d409775c 100644 --- a/src/bin/common/Makefile.common +++ b/src/bin/common/Makefile.common @@ -31,9 +31,7 @@ DEFAULT_CFLAGS += -I $(shell $(PG_CONFIG) --pkgincludedir)/internal DEFAULT_CFLAGS += $(shell $(PG_CONFIG) --cflags) DEFAULT_CFLAGS += -Wformat DEFAULT_CFLAGS += -Wall -DEFAULT_CFLAGS += -Werror=implicit-int -DEFAULT_CFLAGS += -Werror=implicit-function-declaration -DEFAULT_CFLAGS += -Werror=return-type +DEFAULT_CFLAGS += -Werror DEFAULT_CFLAGS += -Wno-declaration-after-statement DEFAULT_CFLAGS += -D_WANT_SEMUN DEFAULT_CFLAGS += -Wno-missing-braces diff --git a/src/bin/pg_autoctl/cli_common.c b/src/bin/pg_autoctl/cli_common.c index 08416e0c6..04c31165a 100644 --- a/src/bin/pg_autoctl/cli_common.c +++ b/src/bin/pg_autoctl/cli_common.c @@ -407,6 +407,14 @@ cli_common_keeper_getopts(int argc, char **argv, break; } + case 'G': + { + /* { "region", required_argument, NULL, 'G' } */ + strlcpy(LocalOptionConfig.region, optarg, NAMEDATALEN); + log_trace("--region %s", LocalOptionConfig.region); + break; + } + case 'V': { /* keeper_cli_print_version prints version and exits. */ diff --git a/src/bin/pg_autoctl/cli_create_node.c b/src/bin/pg_autoctl/cli_create_node.c index c8d9c8a02..39b3f4aab 100644 --- a/src/bin/pg_autoctl/cli_create_node.c +++ b/src/bin/pg_autoctl/cli_create_node.c @@ -343,6 +343,7 @@ cli_create_postgres_getopts(int argc, char **argv) { "candidate-priority", required_argument, NULL, 'P' }, { "replication-quorum", required_argument, NULL, 'r' }, { "maximum-backup-rate", required_argument, NULL, 'R' }, + { "region", required_argument, NULL, 'G' }, { "run", no_argument, NULL, 'x' }, { "no-ssl", no_argument, NULL, 'N' }, { "ssl-self-signed", no_argument, NULL, 's' }, @@ -356,7 +357,7 @@ cli_create_postgres_getopts(int argc, char **argv) int optind = cli_create_node_getopts(argc, argv, long_options, - "C:D:H:p:l:U:A:SLd:a:n:f:m:MI:W:w:RVvqhP:r:xsN", + "C:D:H:p:l:U:A:SLd:a:n:f:m:MI:W:w:RGVvqhP:r:xsN", &options); /* publish our option parsing in the global variable */ @@ -441,6 +442,7 @@ cli_create_coordinator_getopts(int argc, char **argv) { "citus-cluster", required_argument, NULL, 'Z' }, { "candidate-priority", required_argument, NULL, 'P' }, { "replication-quorum", required_argument, NULL, 'r' }, + { "region", required_argument, NULL, 'G' }, { "run", no_argument, NULL, 'x' }, { "no-ssl", no_argument, NULL, 'N' }, { "ssl-self-signed", no_argument, NULL, 's' }, @@ -454,7 +456,7 @@ cli_create_coordinator_getopts(int argc, char **argv) int optind = cli_create_node_getopts(argc, argv, long_options, - "C:D:H:p:l:U:A:SLd:a:n:f:m:MRVvqhzZ:P:r:xsN", + "C:D:H:p:l:U:A:SLd:a:n:f:m:MRGVvqhzZ:P:r:xsN", &options); options.groupId = 0; @@ -551,6 +553,7 @@ cli_create_worker_getopts(int argc, char **argv) { "citus-cluster", required_argument, NULL, 'Z' }, { "candidate-priority", required_argument, NULL, 'P' }, { "replication-quorum", required_argument, NULL, 'r' }, + { "region", required_argument, NULL, 'G' }, { "run", no_argument, NULL, 'x' }, { "no-ssl", no_argument, NULL, 'N' }, { "ssl-self-signed", no_argument, NULL, 's' }, @@ -564,7 +567,7 @@ cli_create_worker_getopts(int argc, char **argv) int optind = cli_create_node_getopts(argc, argv, long_options, - "C:D:H:p:l:y:zZ:U:A:SLd:a:n:f:m:MRVvqhzP:r:xsN", + "C:D:H:p:l:y:zZ:U:A:SLd:a:n:f:m:MRGVvqhzP:r:xsN", &options); if (options.groupId == 0) diff --git a/src/bin/pg_autoctl/cli_watch.c b/src/bin/pg_autoctl/cli_watch.c index 607c0a64e..bc6ac5bfa 100644 --- a/src/bin/pg_autoctl/cli_watch.c +++ b/src/bin/pg_autoctl/cli_watch.c @@ -43,6 +43,8 @@ static int cli_watch_getopts(int argc, char **argv); static void cli_watch(int argc, char **argv); +static bool watchWaitForMonitor = false; + CommandLine watch_command = make_command("watch", "Display a dashboard to watch monitor's events and state", @@ -51,7 +53,8 @@ CommandLine watch_command = " --monitor show the monitor uri\n" " --formation formation to query, defaults to 'default' \n" " --group group to query formation, defaults to all \n" - " --json output data in the JSON format\n", + " --json output data in the JSON format\n" + " --wait wait for the monitor to be ready before starting\n", cli_watch_getopts, cli_watch); @@ -67,6 +70,7 @@ cli_watch_getopts(int argc, char **argv) { "monitor", required_argument, NULL, 'm' }, { "formation", required_argument, NULL, 'f' }, { "group", required_argument, NULL, 'g' }, + { "wait", no_argument, NULL, 'w' }, { "version", no_argument, NULL, 'V' }, { "verbose", no_argument, NULL, 'v' }, { "quiet", no_argument, NULL, 'q' }, @@ -84,7 +88,7 @@ cli_watch_getopts(int argc, char **argv) optind = 0; - while ((c = getopt_long(argc, argv, "D:f:g:n:Vvqh", + while ((c = getopt_long(argc, argv, "D:f:g:n:wVvqh", long_options, &option_index)) != -1) { switch (c) @@ -128,6 +132,13 @@ cli_watch_getopts(int argc, char **argv) break; } + case 'w': + { + watchWaitForMonitor = true; + log_trace("--wait"); + break; + } + case 'V': { /* keeper_cli_print_version prints version and exits. */ @@ -238,6 +249,12 @@ cli_watch(int argc, char **argv) (void) cli_monitor_init_from_option_or_config(&(context.monitor), &config); + if (watchWaitForMonitor) + { + pgsql_set_monitor_interactive_retry_policy( + &(context.monitor.pgsql.retryPolicy)); + } + strlcpy(context.formation, config.formation, sizeof(context.formation)); context.groupId = config.groupId; diff --git a/src/bin/pg_autoctl/defaults.h b/src/bin/pg_autoctl/defaults.h index dd4971421..7873f0d98 100644 --- a/src/bin/pg_autoctl/defaults.h +++ b/src/bin/pg_autoctl/defaults.h @@ -19,7 +19,7 @@ #define PG_AUTOCTL_VERSION GIT_VERSION /* version of the extension that we requite to talk to on the monitor */ -#define PG_AUTOCTL_EXTENSION_VERSION "2.2" +#define PG_AUTOCTL_EXTENSION_VERSION "2.3" /* environment variable to use to make DEBUG facilities available */ #define PG_AUTOCTL_DEBUG "PG_AUTOCTL_DEBUG" diff --git a/src/bin/pg_autoctl/keeper.c b/src/bin/pg_autoctl/keeper.c index 8ec85e9d9..26145c462 100644 --- a/src/bin/pg_autoctl/keeper.c +++ b/src/bin/pg_autoctl/keeper.c @@ -1670,6 +1670,7 @@ keeper_register_and_init(Keeper *keeper, NodeState initialState) config->pgSetup.settings.candidatePriority, config->pgSetup.settings.replicationQuorum, config->pgSetup.citusClusterName, + config->region, &mayRetry, &assignedState)) { @@ -1875,6 +1876,7 @@ keeper_register_again(Keeper *keeper) config->pgSetup.settings.candidatePriority, config->pgSetup.settings.replicationQuorum, DEFAULT_CITUS_CLUSTER_NAME, + config->region, &mayRetry, &assignedState)) { diff --git a/src/bin/pg_autoctl/keeper_config.c b/src/bin/pg_autoctl/keeper_config.c index 23815d28d..0d145b0ec 100644 --- a/src/bin/pg_autoctl/keeper_config.c +++ b/src/bin/pg_autoctl/keeper_config.c @@ -61,6 +61,10 @@ make_strbuf_option("pg_autoctl", "nodekind", NULL, false, NAMEDATALEN, \ config->nodeKind) +#define OPTION_AUTOCTL_REGION(config) \ + make_strbuf_option_default("pg_autoctl", "region", "region", \ + false, NAMEDATALEN, config->region, "") + #define OPTION_POSTGRESQL_PGDATA(config) \ make_strbuf_option("postgresql", "pgdata", "pgdata", true, MAXPGPATH, \ config->pgSetup.pgdata) @@ -227,6 +231,7 @@ OPTION_AUTOCTL_HOSTNAME(config), \ OPTION_AUTOCTL_NODENAME(config), \ OPTION_AUTOCTL_NODEKIND(config), \ + OPTION_AUTOCTL_REGION(config), \ OPTION_POSTGRESQL_PGDATA(config), \ OPTION_POSTGRESQL_PG_CTL(config), \ OPTION_POSTGRESQL_USERNAME(config), \ diff --git a/src/bin/pg_autoctl/keeper_config.h b/src/bin/pg_autoctl/keeper_config.h index 0c71a65e0..0ed9af1d4 100644 --- a/src/bin/pg_autoctl/keeper_config.h +++ b/src/bin/pg_autoctl/keeper_config.h @@ -46,6 +46,7 @@ typedef struct KeeperConfig char name[_POSIX_HOST_NAME_MAX]; char hostname[_POSIX_HOST_NAME_MAX]; char nodeKind[NAMEDATALEN]; + char region[NAMEDATALEN]; /* PostgreSQL setup */ PostgresSetup pgSetup; diff --git a/src/bin/pg_autoctl/monitor.c b/src/bin/pg_autoctl/monitor.c index f44414bc9..af4b446ff 100644 --- a/src/bin/pg_autoctl/monitor.c +++ b/src/bin/pg_autoctl/monitor.c @@ -851,19 +851,20 @@ monitor_register_node(Monitor *monitor, char *formation, NodeState initialState, PgInstanceKind kind, int candidatePriority, bool quorum, char *citusClusterName, + char *region, bool *mayRetry, MonitorAssignedState *assignedState) { PGSQL *pgsql = &monitor->pgsql; const char *sql = "SELECT * FROM pgautofailover.register_node($1, $2, $3, $4, $5, $6, $7, " - "$8, $9::pgautofailover.replication_state, $10, $11, $12, $13)"; - int paramCount = 13; - Oid paramTypes[13] = { + "$8, $9::pgautofailover.replication_state, $10, $11, $12, $13, $14)"; + int paramCount = 14; + Oid paramTypes[14] = { TEXTOID, TEXTOID, INT4OID, NAMEOID, TEXTOID, INT8OID, - INT8OID, INT4OID, TEXTOID, TEXTOID, INT4OID, BOOLOID, TEXTOID + INT8OID, INT4OID, TEXTOID, TEXTOID, INT4OID, BOOLOID, TEXTOID, TEXTOID }; - const char *paramValues[13]; + const char *paramValues[14]; MonitorAssignedStateParseContext parseContext = { { 0 }, assignedState, false }; const char *nodeStateString = NodeStateToString(initialState); @@ -889,6 +890,10 @@ monitor_register_node(Monitor *monitor, char *formation, IS_EMPTY_STRING_BUFFER(citusClusterName) ? DEFAULT_CITUS_CLUSTER_NAME : citusClusterName; + paramValues[13] = + IS_EMPTY_STRING_BUFFER(region) + ? "default" + : region; if (!pgsql_execute_with_params(pgsql, sql, paramCount, paramTypes, paramValues, @@ -1940,7 +1945,7 @@ monitor_get_current_state(Monitor *monitor, char *formation, int group, " current_group_state, assigned_group_state, " " candidate_priority, replication_quorum, " " reported_tli, reported_lsn, health, nodecluster, " - " healthlag, reportlag" + " noderegion, healthlag, reportlag" " FROM pgautofailover.current_state($1) cs " " JOIN (" " select nodeid, " @@ -1966,7 +1971,7 @@ monitor_get_current_state(Monitor *monitor, char *formation, int group, " current_group_state, assigned_group_state, " " candidate_priority, replication_quorum, " " reported_tli, reported_lsn, health, nodecluster, " - " healthlag, reportlag" + " noderegion, healthlag, reportlag" " FROM pgautofailover.current_state($1, $2) cs " " JOIN (" " select nodeid, " @@ -2019,7 +2024,7 @@ parseCurrentNodeState(PGresult *result, int rowNumber, int errors = 0; /* we don't expect any of the column to be NULL */ - for (colNumber = 0; colNumber < 16; colNumber++) + for (colNumber = 0; colNumber < 17; colNumber++) { if (PQgetisnull(result, rowNumber, 0)) { @@ -2044,8 +2049,9 @@ parseCurrentNodeState(PGresult *result, int rowNumber, * 11 - OUT reported_lsn pg_lsn, * 12 - OUT health integer * 13 - OUT nodecluster text - * 14 - healthlag int (extract epoch from interval) - * 15 - reportlag int (extract epoch from interval) + * 14 - OUT noderegion text + * 15 - healthlag int (extract epoch from interval) + * 16 - reportlag int (extract epoch from interval) * * We need the groupId to parse the formation kind into a nodeKind, so we * begin at column 1 and get back to column 0 later, after column 4. @@ -2181,6 +2187,16 @@ parseCurrentNodeState(PGresult *result, int rowNumber, } value = PQgetvalue(result, rowNumber, 14); + length = strlcpy(nodeState->region, value, NAMEDATALEN); + if (length >= NAMEDATALEN) + { + log_error("Region \"%s\" returned by monitor is %d characters, " + "the maximum supported by pg_autoctl is %d", + value, length, NAMEDATALEN - 1); + ++errors; + } + + value = PQgetvalue(result, rowNumber, 15); if (!stringToDouble(value, &(nodeState->healthLag))) { @@ -2188,7 +2204,7 @@ parseCurrentNodeState(PGresult *result, int rowNumber, ++errors; } - value = PQgetvalue(result, rowNumber, 15); + value = PQgetvalue(result, rowNumber, 16); if (!stringToDouble(value, &(nodeState->reportLag))) { @@ -2221,10 +2237,10 @@ parseCurrentNodeStateArray(CurrentNodeStateArray *nodesArray, PGresult *result) return false; } - /* pgautofailover.current_state returns 11 columns */ - if (PQnfields(result) != 16) + /* pgautofailover.current_state returns 17 columns (including noderegion) */ + if (PQnfields(result) != 17) { - log_error("Query returned %d columns, expected 16", PQnfields(result)); + log_error("Query returned %d columns, expected 17", PQnfields(result)); return false; } diff --git a/src/bin/pg_autoctl/monitor.h b/src/bin/pg_autoctl/monitor.h index d18bf16cf..6609bf39c 100644 --- a/src/bin/pg_autoctl/monitor.h +++ b/src/bin/pg_autoctl/monitor.h @@ -140,6 +140,7 @@ bool monitor_register_node(Monitor *monitor, int candidatePriority, bool quorum, char *citusClusterName, + char *region, bool *mayRetry, MonitorAssignedState *assignedState); bool monitor_node_active(Monitor *monitor, diff --git a/src/bin/pg_autoctl/nodespec.c b/src/bin/pg_autoctl/nodespec.c index acf152dc8..afe0e43af 100644 --- a/src/bin/pg_autoctl/nodespec.c +++ b/src/bin/pg_autoctl/nodespec.c @@ -114,6 +114,9 @@ nodespec_read(const char *path, NodeSpec *spec) make_strbuf_option_default("settings", "replication_quorum", NULL, false, sizeof(replicationQuorumStr), replicationQuorumStr, "true"), + make_strbuf_option_default("settings", "region", NULL, false, + sizeof(spec->region), spec->region, + ""), /* [options] — immutable, used only at create time */ make_strbuf_option_default("options", "ssl", NULL, false, @@ -674,6 +677,13 @@ nodespec_create_argv(const NodeSpec *spec, PUSH("false"); } + /* region label (omit when empty — monitor defaults to "default") */ + if (!IS_EMPTY_STRING_BUFFER(spec->region)) + { + PUSH("--region"); + PUSH(spec->region); + } + /* Citus secondary/read-replica cluster settings */ if (spec->citusSecondary) { diff --git a/src/bin/pg_autoctl/nodespec.h b/src/bin/pg_autoctl/nodespec.h index e8505eb61..904c393b6 100644 --- a/src/bin/pg_autoctl/nodespec.h +++ b/src/bin/pg_autoctl/nodespec.h @@ -71,6 +71,7 @@ typedef struct NodeSpec /* [settings] — mutable; applied on SIGHUP / file change */ int candidate_priority; /* 0-100, default 50 */ bool replication_quorum; /* sync quorum participant, default true */ + char region[NAMEDATALEN]; /* data-centre / availability zone label */ /* [options] — immutable; used only at pg_autoctl create time */ char ssl[32]; /* self-signed | verify-ca | verify-full | off */ diff --git a/src/bin/pg_autoctl/nodestate_utils.h b/src/bin/pg_autoctl/nodestate_utils.h index a6cabdd0b..fbdf79f4b 100644 --- a/src/bin/pg_autoctl/nodestate_utils.h +++ b/src/bin/pg_autoctl/nodestate_utils.h @@ -25,6 +25,7 @@ typedef struct CurrentNodeState char formation[NAMEDATALEN]; char citusClusterName[NAMEDATALEN]; + char region[NAMEDATALEN]; int groupId; PgInstanceKind pgKind; diff --git a/src/bin/pg_autoctl/watch.c b/src/bin/pg_autoctl/watch.c index fea9bbeb9..3fccaf927 100644 --- a/src/bin/pg_autoctl/watch.c +++ b/src/bin/pg_autoctl/watch.c @@ -898,6 +898,12 @@ compute_column_size(ColumnType type, NodeAddressHeaders *headers) return headers->maxStateSize; } + case COLUMN_TYPE_REGION: + { + /* "default" is 7 chars; most region names fit in 12 */ + return 12; + } + default: { log_fatal("BUG: compute_column_size(%d)", type); @@ -1085,6 +1091,12 @@ print_node_state(WatchContext *context, ColPolicy *policy, break; } + case COLUMN_TYPE_REGION: + { + mvprintw(r, cc, "%*s", len, nodeState->region); + break; + } + default: { log_fatal("BUG: print_node_state(%d)", cType); diff --git a/src/bin/pg_autoctl/watch_colspecs.h b/src/bin/pg_autoctl/watch_colspecs.h index ad45c7519..f3726581f 100644 --- a/src/bin/pg_autoctl/watch_colspecs.h +++ b/src/bin/pg_autoctl/watch_colspecs.h @@ -27,6 +27,7 @@ typedef enum COLUMN_TYPE_CONN_REPORT_LAG, COLUMN_TYPE_REPORTED_STATE, COLUMN_TYPE_ASSIGNED_STATE, + COLUMN_TYPE_REGION, COLUMN_TYPE_LAST } ColumnType; @@ -38,7 +39,7 @@ typedef struct ColSpec int len; } ColSpec; -#define MAX_COL_SPECS 12 +#define MAX_COL_SPECS 14 typedef struct ColPolicy { @@ -134,6 +135,7 @@ ColPolicy ColumnPolicies[] = { { { COLUMN_TYPE_NAME, "Name", 0 }, { COLUMN_TYPE_ID, "Node", 0 }, + { COLUMN_TYPE_REGION, "Region", 0 }, { COLUMN_TYPE_REPLICATION_QUORUM, "Quorum", 0 }, { COLUMN_TYPE_CANDIDATE_PRIORITY, "Priority", 0 }, { COLUMN_TYPE_CONN_HEALTH_LAG, "Check", 0 }, @@ -150,6 +152,7 @@ ColPolicy ColumnPolicies[] = { { { COLUMN_TYPE_NAME, "Name", 0 }, { COLUMN_TYPE_ID, "Node", 0 }, + { COLUMN_TYPE_REGION, "Region", 0 }, { COLUMN_TYPE_REPLICATION_QUORUM, "Quorum", 0 }, { COLUMN_TYPE_CANDIDATE_PRIORITY, "Priority", 0 }, { COLUMN_TYPE_TLI_LSN, "TLI: LSN", 0 }, @@ -167,6 +170,7 @@ ColPolicy ColumnPolicies[] = { { { COLUMN_TYPE_NAME, "Name", 0 }, { COLUMN_TYPE_ID, "Node", 0 }, + { COLUMN_TYPE_REGION, "Region", 0 }, { COLUMN_TYPE_REPLICATION_QUORUM, "Quorum", 0 }, { COLUMN_TYPE_CANDIDATE_PRIORITY, "Priority", 0 }, { COLUMN_TYPE_HOST_PORT, "Host:Port", 0 }, @@ -185,6 +189,7 @@ ColPolicy ColumnPolicies[] = { { { COLUMN_TYPE_NAME, "Name", 0 }, { COLUMN_TYPE_ID, "Node", 0 }, + { COLUMN_TYPE_REGION, "Region", 0 }, { COLUMN_TYPE_REPLICATION_QUORUM, "Quorum", 0 }, { COLUMN_TYPE_CANDIDATE_PRIORITY, "Priority", 0 }, { COLUMN_TYPE_HOST_PORT, "Host:Port", 0 }, diff --git a/src/bin/pgaftest/cli_indent.c b/src/bin/pgaftest/cli_indent.c index 54a873a91..9b99aa1d3 100644 --- a/src/bin/pgaftest/cli_indent.c +++ b/src/bin/pgaftest/cli_indent.c @@ -450,6 +450,10 @@ print_node(FILE *out, const TestNode *n, int baseIndent) sformat(numbuf, sizeof(numbuf), "%d", n->candidatePriority); ADD("candidate-priority", numbuf); } + if (n->region[0]) + { + ADD("region", n->region); + } if (!n->replicationQuorum) { ADD("replication-quorum", "false"); diff --git a/src/bin/pgaftest/cli_root.c b/src/bin/pgaftest/cli_root.c index 5b724cc2e..1a0c08d2c 100644 --- a/src/bin/pgaftest/cli_root.c +++ b/src/bin/pgaftest/cli_root.c @@ -22,6 +22,10 @@ #include "cli_demo.h" #include "cli_indent.h" +/* forward declarations */ +static void resolve_interactive_context(void); +extern CommandLine pgaftest_root; + /* ----------------------------------------------------------------------- * Shared option parsing * ----------------------------------------------------------------------- */ @@ -33,7 +37,6 @@ typedef struct PgaftestOpts char stepName[64]; char schedule[1024]; char expected[1024]; - bool withTmux; bool noCleanup; /* --no-cleanup: skip compose down after run */ int verbose; } PgaftestOpts; @@ -80,11 +83,81 @@ derive_work_dir(const char *specPath, char *buf, int buflen) } +/* + * pgaftest_last_file — path of the "last active work dir" pointer file. + * Written on every successful cluster startup; read as the default workDir + * when --work-dir is not given and no spec file is available. + */ +static void +pgaftest_last_file(char *buf, int buflen) +{ + const char *tmpdir = getenv("TMPDIR"); /* IGNORE-BANNED */ + if (!tmpdir || *tmpdir == '\0') + { + tmpdir = "/tmp"; + } + sformat(buf, buflen, "%s/pgaftest/.last", tmpdir); +} + + +/* + * pgaftest_write_last — record workDir as the most-recently-started cluster. + */ +static void +pgaftest_write_last(const char *workDir) +{ + char path[1024]; + pgaftest_last_file(path, sizeof(path)); + + FILE *f = fopen(path, "w"); + if (!f) + { + /* non-fatal: .last is a convenience, not required for correctness */ + return; + } + fprintf(f, "%s\n", workDir); + fclose(f); +} + + +/* + * pgaftest_read_last — fill buf with the last active work dir, or leave it + * unchanged if the file doesn't exist or is empty. + */ +static void +pgaftest_read_last(char *buf, int buflen) +{ + char path[1024]; + pgaftest_last_file(path, sizeof(path)); + + FILE *f = fopen(path, "r"); + if (!f) + { + return; + } + + char line[1024] = { 0 }; + if (fgets(line, sizeof(line), f)) + { + /* strip trailing newline */ + char *nl = strchr(line, '\n'); + if (nl) + { + *nl = '\0'; + } + if (line[0] != '\0') + { + strlcpy(buf, line, buflen); + } + } + fclose(f); +} + + static struct option long_options[] = { { "work-dir", required_argument, NULL, 'w' }, { "schedule", required_argument, NULL, 'S' }, { "expected", required_argument, NULL, 'E' }, - { "tmux", no_argument, NULL, 't' }, { "no-cleanup", no_argument, NULL, 'n' }, { "verbose", no_argument, NULL, 'v' }, { "debug", no_argument, NULL, 'd' }, @@ -97,7 +170,9 @@ pgaftest_getopts(int argc, char **argv) { int c, option_index = 0; - while ((c = getopt_long(argc, argv, "w:S:E:tnvdh", + optind = 0; + + while ((c = getopt_long(argc, argv, "w:S:E:nvdh", long_options, &option_index)) != -1) { switch (c) @@ -120,12 +195,6 @@ pgaftest_getopts(int argc, char **argv) break; } - case 't': - { - pgaftestOpts.withTmux = true; - break; - } - case 'n': { pgaftestOpts.noCleanup = true; @@ -301,24 +370,40 @@ cli_setup(int argc, char **argv) { if (argc < 1 || argv[0] == NULL) { - log_error("Usage: pgaftest setup [--tmux] [--work-dir ]"); + log_error("Usage: pgaftest cluster setup [--work-dir ] "); exit(1); } strlcpy(pgaftestOpts.specFile, argv[0], sizeof(pgaftestOpts.specFile)); - /* - * The commandline library stops getopt at the first non-option (the spec - * file path), so flags that follow it — e.g. `pgaftest setup spec --tmux` - * — are not seen on the first pass. Re-run getopts now: argv[0] acts as - * a dummy program name so getopt starts scanning from index 1 onward, - * picking up --tmux, --work-dir, etc. optreset resets BSD/macOS state. - */ -#ifdef __BSD_VISIBLE - optreset = 1; -#endif - optind = 1; - pgaftest_getopts(argc, argv); + if (pgaftestOpts.workDir[0] == '\0') + { + derive_work_dir(pgaftestOpts.specFile, + pgaftestOpts.workDir, sizeof(pgaftestOpts.workDir)); + } + + TestSpec *spec = parse_test_spec(pgaftestOpts.specFile); + if (!spec) + { + exit(1); + } + + pgaftest_write_last(pgaftestOpts.workDir); + bool ok = runner_setup(spec, pgaftestOpts.workDir, false); + exit(ok ? 0 : 1); +} + + +static void +cli_tmux(int argc, char **argv) +{ + if (argc < 1 || argv[0] == NULL) + { + log_error("Usage: pgaftest tmux [--work-dir ] "); + exit(1); + } + + strlcpy(pgaftestOpts.specFile, argv[0], sizeof(pgaftestOpts.specFile)); if (pgaftestOpts.workDir[0] == '\0') { @@ -332,53 +417,87 @@ cli_setup(int argc, char **argv) exit(1); } - bool ok = runner_setup(spec, pgaftestOpts.workDir, - pgaftestOpts.withTmux); + pgaftest_write_last(pgaftestOpts.workDir); + bool ok = runner_setup(spec, pgaftestOpts.workDir, true); exit(ok ? 0 : 1); } /* ----------------------------------------------------------------------- - * pgaftest step + * pgaftest step [] + * + * The spec file is resolved in order: + * 1. explicit second positional argument (a .pgaf path) + * 2. PGAFTEST_SPEC env var (set inside the pgaftest container) + * 3. /spec.pgaf (fixed mount point in the container) + * 4. /spec.pgaf (host-side leftover from a previous setup) * ----------------------------------------------------------------------- */ static void cli_step(int argc, char **argv) { - if (argc < 1 || argv[0] == NULL) + bool autoNext = false; + + /* + * `pgaftest step` with no positional args runs the next (or retries the + * last failed) step automatically using the state file. + * `pgaftest step ` runs that specific step by name. + */ + if (argc >= 1 && argv[0] != NULL && argv[0][0] != '-') { - log_error("Usage: pgaftest step [--work-dir ]"); - exit(1); - } + strlcpy(pgaftestOpts.stepName, argv[0], sizeof(pgaftestOpts.stepName)); - /* step name is positional */ - strlcpy(pgaftestOpts.stepName, argv[0], sizeof(pgaftestOpts.stepName)); + /* Optional spec.pgaf as second positional */ + if (argc >= 2 && argv[1] != NULL && argv[1][0] != '-') + { + strlcpy(pgaftestOpts.specFile, argv[1], + sizeof(pgaftestOpts.specFile)); + } + } + else + { + autoNext = true; + } - /* We need the spec file too — look for it in workDir */ - char specPath[1024]; - sformat(specPath, sizeof(specPath), "%s/spec.pgaf", - pgaftestOpts.workDir); + /* Fill specFile + workDir from env / known paths when not set yet */ + resolve_interactive_context(); - /* If there's a second positional arg, treat it as the spec path */ - if (argc >= 2 && argv[1] != NULL) + if (pgaftestOpts.specFile[0] == '\0') { - strlcpy(specPath, argv[1], sizeof(specPath)); + if (pgaftestOpts.workDir[0] != '\0') + { + sformat(pgaftestOpts.specFile, sizeof(pgaftestOpts.specFile), + "%s/spec.pgaf", pgaftestOpts.workDir); + } + else + { + log_error("No spec file: pass , set PGAFTEST_SPEC, " + "or use --work-dir"); + exit(EXIT_CODE_BAD_ARGS); + } } - /* derive work dir from spec path when not given explicitly */ if (pgaftestOpts.workDir[0] == '\0') { - derive_work_dir(specPath, pgaftestOpts.workDir, - sizeof(pgaftestOpts.workDir)); + derive_work_dir(pgaftestOpts.specFile, + pgaftestOpts.workDir, sizeof(pgaftestOpts.workDir)); } - TestSpec *spec = parse_test_spec(specPath); + TestSpec *spec = parse_test_spec(pgaftestOpts.specFile); if (!spec) { exit(1); } - bool ok = runner_step(spec, pgaftestOpts.workDir, - pgaftestOpts.stepName); + bool ok; + if (autoNext) + { + ok = runner_step_next(spec, pgaftestOpts.workDir); + } + else + { + ok = runner_step(spec, pgaftestOpts.workDir, pgaftestOpts.stepName); + } + exit(ok ? 0 : 1); } @@ -415,26 +534,158 @@ cli_prepare(int argc, char **argv) /* ----------------------------------------------------------------------- - * pgaftest show + * pgaftest show — sub-command set + * + * show compose print the generated docker-compose.yml + * show spec print the spec in canonical (indented) form + * show step list steps with * on next / ! on failed + * show services list the compose service names * ----------------------------------------------------------------------- */ + +/* + * Shared spec resolution for show sub-commands: accept an optional positional + * spec path, then fall back to env / /spec.pgaf. + */ +static TestSpec * +show_resolve_spec(int argc, char **argv) +{ + if (argc >= 1 && argv[0] && argv[0][0] != '-' && + strstr(argv[0], ".pgaf") != NULL) + { + strlcpy(pgaftestOpts.specFile, argv[0], sizeof(pgaftestOpts.specFile)); + } + resolve_interactive_context(); + if (pgaftestOpts.specFile[0] == '\0') + { + log_error("No spec file: pass or set PGAFTEST_SPEC"); + exit(EXIT_CODE_BAD_ARGS); + } + if (pgaftestOpts.workDir[0] == '\0') + { + derive_work_dir(pgaftestOpts.specFile, + pgaftestOpts.workDir, sizeof(pgaftestOpts.workDir)); + } + TestSpec *spec = parse_test_spec(pgaftestOpts.specFile); + if (!spec) + { + exit(1); + } + return spec; +} + + static void -cli_show(int argc, char **argv) +cli_show_compose(int argc, char **argv) { - if (argc < 1 || argv[0] == NULL) + TestSpec *spec = show_resolve_spec(argc, argv); + bool ok = runner_show(spec); + exit(ok ? 0 : 1); +} + + +static void +cli_show_spec(int argc, char **argv) +{ + TestSpec *spec = show_resolve_spec(argc, argv); + + /* Re-print the spec source — the canonical copy is at specFile itself */ + FILE *f = fopen(pgaftestOpts.specFile, "r"); /* IGNORE-BANNED */ + if (!f) { - log_error("Usage: pgaftest show "); + log_error("Cannot open \"%s\": %m", pgaftestOpts.specFile); exit(1); } + char buf[4096]; + size_t n; + while ((n = fread(buf, 1, sizeof(buf), f)) > 0) + { + fwrite(buf, 1, n, stdout); + } + fclose(f); + (void) spec; /* parsed for validation; content comes from the file */ + exit(0); +} - strlcpy(pgaftestOpts.specFile, argv[0], sizeof(pgaftestOpts.specFile)); - TestSpec *spec = parse_test_spec(pgaftestOpts.specFile); - if (!spec) +static void +cli_show_steps(int argc, char **argv) +{ + TestSpec *spec = show_resolve_spec(argc, argv); + + TestRunnerState st; + bool hasState = runner_state_read(pgaftestOpts.workDir, &st); + + for (int i = 0; i < spec->sequenceLength; i++) { + const char *name = spec->sequence[i]; + + if (!hasState) + { + /* No state yet — mark index 0 as the pending next step */ + fformat(stdout, "%s %s\n", + (i == 0) ? "*" : " ", name); + } + else if (!st.last_ok && strcmp(name, st.last_step) == 0) + { + /* Last step failed — mark it for retry */ + fformat(stdout, "! %s\n", name); + } + else if (i == st.current) + { + /* This is the next step to run */ + fformat(stdout, "* %s\n", name); + } + else if (i < st.current) + { + fformat(stdout, " %s\n", name); + } + else + { + fformat(stdout, " %s\n", name); + } + } + exit(0); +} + + +static void +cli_show_step(int argc, char **argv) +{ + TestSpec *spec = show_resolve_spec(argc, argv); + + TestRunnerState st; + runner_state_read(pgaftestOpts.workDir, &st); + + int idx = st.current; + if (idx >= spec->sequenceLength) + { + fformat(stdout, "All %d steps complete.\n", spec->sequenceLength); + exit(0); + } + + const char *name = spec->sequence[idx]; + TestStep *step = spec_find_step(spec, name); + if (!step) + { + log_error("Step \"%s\" not found in spec", name); exit(1); } - bool ok = runner_show(spec); + fformat(stdout, "step %s {\n", name); + for (TestCmd *cmd = step->commands; cmd != NULL; cmd = cmd->next) + { + test_cmd_print(stdout, cmd, 4); + } + fformat(stdout, "}\n"); + exit(0); +} + + +static void +cli_show_state(int argc, char **argv) +{ + TestSpec *spec = show_resolve_spec(argc, argv); + bool ok = runner_show_state(spec, pgaftestOpts.workDir); exit(ok ? 0 : 1); } @@ -442,6 +693,33 @@ cli_show(int argc, char **argv) /* ----------------------------------------------------------------------- * pgaftest down * ----------------------------------------------------------------------- */ +static void +cli_sh(int argc, char **argv) +{ + resolve_interactive_context(); + + if (pgaftestOpts.workDir[0] == '\0') + { + log_error("Cannot determine work directory: " + "provide --work-dir, a spec file argument, " + "or run from inside the pgaftest container"); + exit(1); + } + + const char *base = strrchr(pgaftestOpts.workDir, '/'); + const char *projectName = (base && *(base + 1)) ? base + 1 + : pgaftestOpts.workDir; + + char cmd[2048]; + sformat(cmd, sizeof(cmd), + "docker compose -p %s -f %s/docker-compose.yml run --rm -it --name %s-sh setup bash", + projectName, pgaftestOpts.workDir, projectName); + + int rc = system(cmd); + exit(rc == 0 ? 0 : 1); +} + + static void cli_down(int argc, char **argv) { @@ -542,6 +820,151 @@ cli_run_setup_only(int argc, char **argv) } bool ok = runner_run_setup_only(spec, pgaftestOpts.workDir); + if (!ok) + { + exit(1); + } + + /* Print step list and usage hint directly to the tty. */ + fformat(stdout, "\n"); + if (spec->sequenceLength > 0) + { + fformat(stdout, "Steps:"); + for (int i = 0; i < spec->sequenceLength; i++) + { + fformat(stdout, " %s", spec->sequence[i]); + } + fformat(stdout, "\n"); + } + fformat(stdout, + "Try: pgaftest step" + " | pgaftest network disconnect " + " | pgaftest show state | pgaftest down\n\n"); + + /* + * Replace this process with bash so the tmux pane becomes an + * interactive shell without opening a new process layer. + */ + execlp("bash", "bash", NULL); + + /* execlp only returns on error */ + log_error("Failed to exec bash: %m"); + exit(1); +} + + +/* ----------------------------------------------------------------------- + * Shared helper: resolve spec + work-dir for interactive sub-commands. + * + * When running inside the pgaftest container (set up by --tmux), the + * compose stack injects: + * PGAFTEST_SPEC = /spec.pgaf + * PGAFTEST_HOST_WORK_DIR = (same abs path bind-mounted) + * + * Priority: explicit CLI arg > env var > /spec.pgaf in CWD. + * ----------------------------------------------------------------------- */ +static void +resolve_interactive_context(void) +{ + if (pgaftestOpts.specFile[0] == '\0') + { + const char *envSpec = getenv("PGAFTEST_SPEC"); /* IGNORE-BANNED */ + if (envSpec && *envSpec) + { + strlcpy(pgaftestOpts.specFile, envSpec, sizeof(pgaftestOpts.specFile)); + } + else if (access("/spec.pgaf", R_OK) == 0) + { + strlcpy(pgaftestOpts.specFile, "/spec.pgaf", sizeof(pgaftestOpts.specFile)); + } + } + + if (pgaftestOpts.workDir[0] == '\0') + { + const char *envWork = getenv("PGAFTEST_HOST_WORK_DIR"); /* IGNORE-BANNED */ + if (envWork && *envWork) + { + strlcpy(pgaftestOpts.workDir, envWork, sizeof(pgaftestOpts.workDir)); + } + else if (pgaftestOpts.specFile[0]) + { + derive_work_dir(pgaftestOpts.specFile, + pgaftestOpts.workDir, sizeof(pgaftestOpts.workDir)); + } + else + { + /* last resort: most recently started cluster */ + pgaftest_read_last(pgaftestOpts.workDir, sizeof(pgaftestOpts.workDir)); + } + } +} + + +/* ----------------------------------------------------------------------- + * pgaftest sql "" + * ----------------------------------------------------------------------- */ +static void +cli_sql(int argc, char **argv) +{ + if (argc < 2) + { + log_error("Usage: pgaftest sql \"\""); + exit(EXIT_CODE_BAD_ARGS); + } + + const char *service = argv[0]; + const char *query = argv[1]; + + resolve_interactive_context(); + + if (pgaftestOpts.specFile[0] == '\0') + { + log_error("No spec file: pass one as argument or set PGAFTEST_SPEC"); + exit(EXIT_CODE_BAD_ARGS); + } + + TestSpec *spec = parse_test_spec(pgaftestOpts.specFile); + if (!spec) + { + exit(1); + } + + bool ok = runner_sql(spec, pgaftestOpts.workDir, service, query); + exit(ok ? 0 : 1); +} + + +/* ----------------------------------------------------------------------- + * pgaftest network connect|disconnect + * ----------------------------------------------------------------------- */ +static void +cli_network(int argc, char **argv) +{ + if (argc < 2 || + (strcmp(argv[0], "connect") != 0 && strcmp(argv[0], "disconnect") != 0)) + { + log_error("Usage: pgaftest network connect|disconnect "); + exit(EXIT_CODE_BAD_ARGS); + } + + bool connect = (strcmp(argv[0], "connect") == 0); + const char *nodeName = argv[1]; + + resolve_interactive_context(); + + if (pgaftestOpts.specFile[0] == '\0') + { + log_error("No spec file: pass one as argument or set PGAFTEST_SPEC"); + exit(EXIT_CODE_BAD_ARGS); + } + + TestSpec *spec = parse_test_spec(pgaftestOpts.specFile); + if (!spec) + { + exit(1); + } + + bool ok = runner_network(spec, pgaftestOpts.workDir, nodeName, connect); exit(ok ? 0 : 1); } @@ -569,7 +992,6 @@ static CommandLine setup_command = make_command("setup", "Bring up a cluster from a spec file (interactive mode)", "[options] ", - " --tmux Launch a tmux session after setup\n" " --work-dir Working directory\n" " (default: $TMPDIR/pgaftest/)\n" " --verbose Enable DEBUG log level\n" @@ -583,12 +1005,62 @@ static CommandLine step_command = " --work-dir Working directory (default: /tmp/pgaftest)\n", pgaftest_getopts, cli_step); +static CommandLine show_compose_command = + make_command("compose", + "Print the generated docker-compose.yml", + "[]", + " Path to spec (default: PGAFTEST_SPEC or /spec.pgaf)\n", + pgaftest_getopts, cli_show_compose); + +static CommandLine show_spec_command = + make_command("spec", + "Print the spec file source", + "[]", + " Path to spec (default: PGAFTEST_SPEC or /spec.pgaf)\n", + pgaftest_getopts, cli_show_spec); + +static CommandLine show_steps_command = + make_command("steps", + "List steps in sequence order with * on the current/next step", + "[]", + " Path to spec (default: PGAFTEST_SPEC or /spec.pgaf)\n" + "\n" + " Markers: *=next to run !=failed (will retry) (space)=done\n", + pgaftest_getopts, cli_show_steps); + +static CommandLine show_step_command = + make_command("step", + "Show commands for the next step to run", + "[]", + " Path to spec (default: PGAFTEST_SPEC or /spec.pgaf)\n", + pgaftest_getopts, cli_show_step); + +static CommandLine show_state_command = + make_command("state", + "Show pg_autoctl show state output with step progress header", + "[]", + " Path to spec (default: PGAFTEST_SPEC or /spec.pgaf)\n", + pgaftest_getopts, cli_show_state); + +static CommandLine *show_subcommands[] = { + &show_compose_command, + &show_spec_command, + &show_steps_command, + &show_step_command, + &show_state_command, + NULL +}; + static CommandLine show_command = - make_command("show", - "Print the docker-compose.yml that would be generated", - "[options] ", - "", - pgaftest_getopts, cli_show); + make_command_set("show", + "Show information about a spec or running cluster", + " []", + " compose Print the generated docker-compose.yml\n" + " spec Print the spec file source\n" + " steps List steps with * on next / ! on failed\n" + " step Show commands for the next step\n" + " state Show pg_autoctl show state with step header\n", + pgaftest_getopts, show_subcommands); static CommandLine prepare_command = make_command("prepare", @@ -605,6 +1077,41 @@ static CommandLine down_command = " --work-dir Working directory (default: /tmp/pgaftest)\n", pgaftest_getopts, cli_down); +static CommandLine sh_command = + make_command("sh", + "Open a bash shell in the running pgaftest container", + "[options]", + " --work-dir Working directory (default: derived from spec)\n", + pgaftest_getopts, cli_sh); + +static CommandLine *cluster_subcommands[] = { + &setup_command, + &prepare_command, + &down_command, + &sh_command, + NULL +}; + +static CommandLine cluster_command = + make_command_set("cluster", + "Manage the cluster lifecycle (bring up, prepare, tear down)", + " [options]", + " setup Bring up a cluster interactively\n" + " prepare Write compose files + Makefile to a directory\n" + " down Tear down the cluster\n" + " sh Open a bash shell in the pgaftest container\n", + pgaftest_getopts, cluster_subcommands); + +static CommandLine tmux_command = + make_command("tmux", + "Bring up a cluster and launch a tmux session", + "[options] ", + " --work-dir Working directory\n" + " (default: $TMPDIR/pgaftest/)\n" + " --verbose Enable DEBUG log level\n" + " --debug Enable TRACE log level\n", + pgaftest_getopts, cli_tmux); + extern void cli_indent(int argc, char **argv); static CommandLine indent_command = @@ -621,14 +1128,49 @@ static CommandLine internal_setup_command = "", pgaftest_getopts, cli_run_setup_only); +static CommandLine sql_command = + make_command("sql", + "Run a SQL query on a named node and print the result (interactive)", + " \"\"", + " Service name (node1, node2, monitor, …)\n" + " SQL statement (quote it)\n", + pgaftest_getopts, cli_sql); + +static CommandLine network_command = + make_command("network", + "Connect or disconnect a node from the compose network (interactive)", + "connect|disconnect ", + " connect Restore the node's network access\n" + " disconnect Sever the node's network access\n", + pgaftest_getopts, cli_network); + +static void +cli_help(int argc, char **argv) +{ + (void) argc; + (void) argv; + commandline_print_command_tree(&pgaftest_root, stdout); + exit(0); +} + + +static CommandLine help_command = + make_command("help", + "Show this help message", + "", + "", + pgaftest_getopts, cli_help); + static CommandLine *root_subcommands[] = { &run_command, - &setup_command, + &cluster_command, + &tmux_command, &step_command, &show_command, - &prepare_command, - &down_command, &indent_command, + &sql_command, + &network_command, + &help_command, &internal_setup_command, &pgaftest_demo_command, NULL @@ -638,12 +1180,14 @@ CommandLine pgaftest_root = make_command_set("pgaftest", "pg_auto_failover test runner", "[command] [options]", - " run Run a .pgaf spec (CI mode)\n" - " setup Bring up a cluster interactively\n" - " step Run one named step\n" - " show Print generated docker-compose.yml\n" - " prepare Write compose files + Makefile to a directory\n" - " down Tear down the cluster\n" - " indent Rewrite a spec with canonical indentation\n" - " demo Demo application\n", - NULL, root_subcommands); + " run Run a .pgaf spec (CI mode)\n" + " cluster Manage the cluster lifecycle\n" + " tmux Bring up a cluster with a tmux session\n" + " step Run one named step\n" + " show Show information (compose, spec, steps, step, state)\n" + " indent Rewrite a spec with canonical indentation\n" + " sql Run SQL on a node and print the result\n" + " network Connect or disconnect a node from the network\n" + " help Show this help message\n" + " demo Demo application\n", + pgaftest_getopts, root_subcommands); diff --git a/src/bin/pgaftest/compose_gen.c b/src/bin/pgaftest/compose_gen.c index d17a6817f..22b01c891 100644 --- a/src/bin/pgaftest/compose_gen.c +++ b/src/bin/pgaftest/compose_gen.c @@ -498,7 +498,8 @@ compose_gen_write(TestCluster *cluster, const char *projectName, const char *contextDir, const char *specFile, - const char *specDir) + const char *specDir, + bool interactive) { FILE *f = fopen(path, "w"); /* IGNORE-BANNED */ if (!f) @@ -817,9 +818,22 @@ compose_gen_write(TestCluster *cluster, */ if (specFile) { - /* Determine which service pgaftest must wait for before starting. */ - /* It needs the cluster fully ready: monitor healthy + all nodes started. */ - fformat(f, " pgaftest:\n"); + /* + * In interactive mode the service is named "setup" and carries a + * profile so that `docker compose up` ignores it entirely — it is + * only invoked via `docker compose run setup`. This avoids the need + * for --scale pgaftest=0 and prevents Compose from rebuilding cluster + * images on every `pgaftest tmux` invocation. + * + * In CI mode the service is named "pgaftest" with no profile so that + * `docker compose up --exit-code-from pgaftest` works as expected. + */ + const char *svcName = interactive ? "setup" : "pgaftest"; + fformat(f, " %s:\n", svcName); + if (interactive) + { + fformat(f, " profiles: [setup]\n"); + } write_image_stanza_target(f, cluster, contextDir, "pgaftest"); /* Build monitor pguri for PG_AUTOCTL_MONITOR */ @@ -858,24 +872,43 @@ compose_gen_write(TestCluster *cluster, strlcpy(workDir, ".", sizeof(workDir)); } + /* + * Add the GID of /var/run/docker.sock as a supplementary group so + * the container's `docker` user can access the socket. The GID + * differs between hosts (e.g. 1 on macOS Docker Desktop, 999 on + * most Linux distros), so we stat it at compose-generation time and + * inject it via `group_add`. + */ + struct stat sockStat; + gid_t dockerSockGid = 0; + if (stat("/var/run/docker.sock", &sockStat) == 0) /* IGNORE-BANNED */ + { + dockerSockGid = sockStat.st_gid; + } + fformat(f, - " user: root\n" + " user: docker\n" + " group_add:\n" + " - \"%u\"\n" + " working_dir: /var/lib/postgres\n" " volumes:\n" - " - %s:/spec.pgaf:ro\n" + " - %s:/var/lib/postgres/spec.pgaf:ro\n" " - /var/run/docker.sock:/var/run/docker.sock\n" - " - %s:%s:ro\n", + " - %s:%s\n", + (unsigned int) dockerSockGid, specFile, workDir, workDir); if (ssl_needs_certs(cluster->ssl)) { fformat(f, - " - %s/ssl/ca.crt:/root/.postgresql/root.crt:ro\n" - " - %s/ssl/client/postgresql.crt:/root/.postgresql/postgresql.crt:ro\n" - " - %s/ssl/client/postgresql.key:/root/.postgresql/postgresql.key:ro\n", + " - %s/ssl/ca.crt:/var/lib/postgres/.postgresql/root.crt:ro\n" + " - %s/ssl/client/postgresql.crt:/var/lib/postgres/.postgresql/postgresql.crt:ro\n" + " - %s/ssl/client/postgresql.key:/var/lib/postgres/.postgresql/postgresql.key:ro\n", workDir, workDir, workDir); } fformat(f, " environment:\n" - " PGAFTEST_COMPOSE_SERVICE: \"1\"\n" + " PGAFTEST_IN_CONTAINER: \"1\"\n" + " PGAFTEST_SPEC: \"/var/lib/postgres/spec.pgaf\"\n" " PGAFTEST_HOST_WORK_DIR: \"%s\"\n" " COMPOSE_PROJECT_NAME: \"%s\"\n", workDir, projectName); @@ -891,7 +924,21 @@ compose_gen_write(TestCluster *cluster, " condition: service_healthy\n", firstNode->name); } - fformat(f, " command: [\"pgaftest\", \"run\", \"/spec.pgaf\"]\n\n"); + + /* + * CI mode: run the full spec to completion (exit code drives CI). + * Interactive mode: no command — docker compose run supplies it. + */ + if (!interactive) + { + fformat(f, + " command: [\"pgaftest\", \"run\"," + " \"/var/lib/postgres/spec.pgaf\"]\n\n"); + } + else + { + fformat(f, "\n"); + } } /* ---- volumes ---- */ @@ -1263,6 +1310,11 @@ compose_gen_write_node_ini(const TestCluster *cluster, node->candidatePriority, node->replicationQuorum ? "true" : "false"); + if (node->region[0]) + { + fformat(f, "region = %s\n", node->region); + } + /* Citus role/cluster settings live in their own [citus] section */ if (node->citusSecondary || node->citusClusterName[0]) { diff --git a/src/bin/pgaftest/compose_gen.h b/src/bin/pgaftest/compose_gen.h index f82d0a4b9..598393b65 100644 --- a/src/bin/pgaftest/compose_gen.h +++ b/src/bin/pgaftest/compose_gen.h @@ -30,13 +30,16 @@ bool compose_gen_write_ssl_certs(const TestCluster *cluster, * specDir is the directory containing the spec (dirname(specFile)); it is * bind-mounted read-only at /etc/pgaf/specs in every data-node container so * that static JSON or other helper files shipped next to the spec can be - * referenced in exec commands. Pass NULL to omit the mount. */ + * referenced in exec commands. Pass NULL to omit the mount. + * interactive: when true the pgaftest service uses `sleep infinity` instead + * of `pgaftest run /spec.pgaf`, leaving it alive for an interactive shell. */ bool compose_gen_write(TestCluster *cluster, const char *path, const char *projectName, const char *contextDir, const char *specFile, - const char *specDir); + const char *specDir, + bool interactive); /* * Write a pg_autoctl_node.ini for the second (replacement) monitor into `dir`. diff --git a/src/bin/pgaftest/test_runner.c b/src/bin/pgaftest/test_runner.c index eedb40e91..96d83a17a 100644 --- a/src/bin/pgaftest/test_runner.c +++ b/src/bin/pgaftest/test_runner.c @@ -20,6 +20,7 @@ #include "string_utils.h" #include "log.h" #include "compose_gen.h" +#include "parson.h" /* binary path set by main() for use in tmux pane commands */ extern char pg_autoctl_program[]; @@ -44,6 +45,175 @@ static bool runner_wait_assigned_goal(TestRunner *r, const char *nodeName, const char *targetState, int timeoutSecs); static void log_output(const char *prefix, const char *out); +/* ----------------------------------------------------------------------- + * DSL pretty-printer + * ----------------------------------------------------------------------- */ +void +test_cmd_print(FILE *f, const TestCmd *cmd, int indent) +{ + char pad[64] = ""; + for (int i = 0; i < indent && i < (int) sizeof(pad) - 1; i++) + { + pad[i] = ' '; + } + pad[indent < (int) sizeof(pad) - 1 ? indent : (int) sizeof(pad) - 1] = '\0'; + + switch (cmd->kind) + { + case CMD_EXEC: + { + fprintf(f, "%sexec %s %s\n", pad, cmd->service, cmd->args); + break; + } + + case CMD_EXEC_FAILS: + { + fprintf(f, "%sexec-fails %s %s\n", pad, cmd->service, cmd->args); + break; + } + + case CMD_WAIT_STATE: + { + if (cmd->timeoutSeconds > 0) + { + fprintf(f, "%swait until %s state = %s timeout %ds\n", + pad, cmd->service, cmd->state, cmd->timeoutSeconds); + } + else + { + fprintf(f, "%swait until %s state = %s\n", + pad, cmd->service, cmd->state); + } + break; + } + + case CMD_ASSERT_STATE: + { + fprintf(f, "%sassert %s state = %s\n", + pad, cmd->service, cmd->state); + break; + } + + case CMD_ASSERT_ASSIGNED: + { + fprintf(f, "%sassert %s assigned-state = %s\n", + pad, cmd->service, cmd->state); + break; + } + + case CMD_SQL: + { + fprintf(f, "%ssql %s { %s }\n", pad, cmd->service, cmd->args); + break; + } + + case CMD_EXPECT: + { + fprintf(f, "%sexpect { %s }\n", pad, cmd->expected); + break; + } + + case CMD_EXPECT_ERROR: + { + if (cmd->state[0]) + { + fprintf(f, "%sexpect error %s\n", pad, cmd->state); + } + else + { + fprintf(f, "%sexpect error\n", pad); + } + break; + } + + case CMD_NETWORK_OFF: + { + fprintf(f, "%snetwork disconnect %s\n", pad, cmd->service); + break; + } + + case CMD_NETWORK_ON: + { + fprintf(f, "%snetwork connect %s\n", pad, cmd->service); + break; + } + + case CMD_SLEEP: + { + fprintf(f, "%ssleep %ds\n", pad, cmd->timeoutSeconds); + break; + } + + case CMD_COMPOSE_DOWN: + { + fprintf(f, "%scompose down\n", pad); + break; + } + + case CMD_COMPOSE_START: + { + fprintf(f, "%scompose start %s\n", pad, cmd->service); + break; + } + + case CMD_COMPOSE_STOP: + { + fprintf(f, "%scompose stop %s\n", pad, cmd->service); + break; + } + + case CMD_COMPOSE_KILL: + { + fprintf(f, "%scompose kill %s\n", pad, cmd->service); + break; + } + + case CMD_STOP_POSTGRES: + { + fprintf(f, "%sstop postgres %s\n", pad, cmd->service); + break; + } + + case CMD_START_POSTGRES: + { + fprintf(f, "%sstart postgres %s\n", pad, cmd->service); + break; + } + + case CMD_PROMOTE: + { + fprintf(f, "%spromote", pad); + for (int i = 0; i < cmd->promoteCount; i++) + { + fprintf(f, " %s%s", cmd->promoteNodes[i], + (i < cmd->promoteCount - 1) ? "," : ""); + } + fprintf(f, "\n"); + break; + } + + case CMD_SET_MONITOR: + { + fprintf(f, "%sset monitor %s\n", pad, cmd->service); + break; + } + + case CMD_LOGS_CHECK: + { + fprintf(f, "%slogs %s%s %s\n", pad, cmd->service, + cmd->logsNegate ? " not" : "", cmd->args); + break; + } + + default: + { + fprintf(f, "%s# (cmd kind %d)\n", pad, (int) cmd->kind); + break; + } + } +} + + /* ----------------------------------------------------------------------- * Internal helpers * ----------------------------------------------------------------------- */ @@ -171,8 +341,9 @@ runner_init(TestRunner *r, TestSpec *spec, const char *workDir) /* * Project name: inside the compose network COMPOSE_PROJECT_NAME is - * authoritative (the container is invoked with /spec.pgaf which would - * otherwise yield "spec"). On the host, derive from the spec filename. + * authoritative. On the host, derive from the work directory basename + * (e.g. /tmp/pgaftest/basic_operation → "basic_operation"). This is + * stable even when the spec is loaded from the in-workdir spec.pgaf copy. */ const char *envProject = getenv("COMPOSE_PROJECT_NAME"); /* IGNORE-BANNED */ if (envProject && *envProject) @@ -181,14 +352,9 @@ runner_init(TestRunner *r, TestSpec *spec, const char *workDir) } else { - const char *base = strrchr(spec->filename, '/'); - base = base ? base + 1 : spec->filename; + const char *base = strrchr(workDir, '/'); + base = base ? base + 1 : workDir; strlcpy(r->projectName, base, sizeof(r->projectName)); - char *dot = strrchr(r->projectName, '.'); - if (dot) - { - *dot = '\0'; - } } sformat(r->workDir, sizeof(r->workDir), "%s", workDir); @@ -200,7 +366,7 @@ runner_init(TestRunner *r, TestSpec *spec, const char *workDir) * and is not accessible from the container. Docker Compose v2 can exec * into a running project by project-name alone; omit -f in that case. */ - if (getenv("PGAFTEST_COMPOSE_SERVICE")) /* IGNORE-BANNED */ + if (getenv("PGAFTEST_IN_CONTAINER")) /* IGNORE-BANNED */ { /* * Inside the pgaftest container, the compose file lives on the HOST @@ -384,20 +550,26 @@ runner_compose_generate(TestRunner *r) } /* - * In host mode (no PGAFTEST_COMPOSE_SERVICE) we ARE the test runner, so - * we don't want the compose file to include a pgaftest service — it only - * makes sense for the in-compose CI mode where `docker compose up - * --exit-code-from pgaftest` drives the whole run. Pass NULL to omit it. + * Include the pgaftest service in the compose file when: + * - running inside a compose network (PGAFTEST_IN_CONTAINER is set), + * so `docker compose up --exit-code-from pgaftest` drives the CI run; + * - or when interactive (--tmux), so the user gets a shell inside the + * pgaftest container with the binary, Docker CLI, and full env ready. + * + * In plain host mode (no --tmux, no PGAFTEST_IN_CONTAINER) the service + * is omitted: the host process itself is the runner. */ - const char *specFileForCompose = getenv("PGAFTEST_COMPOSE_SERVICE") /* IGNORE-BANNED */ - ? r->specFile : NULL; + bool inCompose = getenv("PGAFTEST_IN_CONTAINER") != NULL; /* IGNORE-BANNED */ + const char *specFileForCompose = + (inCompose || r->interactive) ? r->specFile : NULL; if (!compose_gen_write(&r->spec->cluster, r->composeFile, r->projectName, r->contextDir, specFileForCompose, - r->hostSpecDir)) + r->hostSpecDir, + r->interactive)) { return false; } @@ -433,6 +605,27 @@ runner_compose_generate(TestRunner *r) } } + /* + * Copy the spec file into the work dir as spec.pgaf so that + * `pgaftest step` can find it without the user needing to supply + * the original path again. + */ + { + char dest[MAXPGPATH]; + sformat(dest, sizeof(dest), "%s/spec.pgaf", r->workDir); + + if (strcmp(r->specFile, dest) != 0) + { + char cmd[2 * MAXPGPATH + 16]; + sformat(cmd, sizeof(cmd), "cp %s %s", r->specFile, dest); + if (system(cmd) != 0) + { + log_error("Failed to copy spec file to \"%s\"", dest); + return false; + } + } + } + return true; } @@ -539,7 +732,7 @@ runner_compose_down(TestRunner *r) * "compose down" sends SIGKILL to our own container, so skip it — the host * runner already calls "compose down" after we exit. */ - if (getenv("PGAFTEST_COMPOSE_SERVICE")) /* IGNORE-BANNED */ + if (getenv("PGAFTEST_IN_CONTAINER")) /* IGNORE-BANNED */ { r->composeUp = false; return true; @@ -835,7 +1028,7 @@ runner_notify_connect(TestRunner *r) char connstr[512]; - if (getenv("PGAFTEST_COMPOSE_SERVICE")) /* IGNORE-BANNED */ + if (getenv("PGAFTEST_IN_CONTAINER")) /* IGNORE-BANNED */ { /* * Inside the compose network: connect directly via the monitor service @@ -3672,7 +3865,7 @@ runner_load_state(TestRunner *r) /* ----------------------------------------------------------------------- * Monitor readiness ping loop * - * When running inside the compose network (PGAFTEST_COMPOSE_SERVICE=1) + * When running inside the compose network (PGAFTEST_IN_CONTAINER=1) * the pgaftest container starts at the same time as the monitor — no * depends_on ordering. We spin here until the monitor postgres accepts * connections, then open the LISTEN channel. @@ -3841,11 +4034,11 @@ runner_run(TestSpec *spec, const char *workDir, bool noCleanup) * The compose file does not include a pgaftest service in host mode — the * current process IS the test runner and has docker access already. * - * When PGAFTEST_COMPOSE_SERVICE is set the compose file was generated to + * When PGAFTEST_IN_CONTAINER is set the compose file was generated to * include a pgaftest service and we're running inside that container; skip * compose up since the stack is already running. */ - if (!getenv("PGAFTEST_COMPOSE_SERVICE")) /* IGNORE-BANNED */ + if (!getenv("PGAFTEST_IN_CONTAINER")) /* IGNORE-BANNED */ { log_info("Starting compose stack (project: %s)", r.projectName); @@ -3997,6 +4190,19 @@ runner_setup(TestSpec *spec, const char *workDir, bool withTmux) { TestRunner r; runner_init(&r, spec, workDir); + r.interactive = withTmux; + + if (withTmux) + { + char version[128] = ""; + int rc = run_cmd_capture(version, sizeof(version), "tmux -V"); + if (rc != 0 || version[0] == '\0') + { + log_error("tmux not found — install tmux before using 'pgaftest tmux'"); + return false; + } + log_debug("tmux version: %s", version); + } if (!runner_compose_generate(&r)) { @@ -4008,10 +4214,27 @@ runner_setup(TestSpec *spec, const char *workDir, bool withTmux) return false; } - if (!runner_wait_for_monitor(&r)) + /* + * In tmux (interactive) mode, docker compose up -d already waited for the + * full depends_on: service_healthy chain before returning — the monitor is + * provably up and all nodes have started. Opening a LISTEN connection from + * the host is unnecessary and fragile (Docker Desktop for Mac routes + * published-port traffic via 192.168.65.1, which is outside the monitor's + * pg_hba trust CIDR). Skip runner_wait_for_monitor; apply formation + * settings directly via docker compose exec, which works on the internal + * network without any host→monitor libpq connection. + * + * In CI mode (pgaftest run) the host process drives every step via + * LISTEN/NOTIFY and does need the connection — runner_wait_for_monitor + * is called from runner_run instead. + */ + if (!withTmux) { - runner_compose_down(&r); - return false; + if (!runner_wait_for_monitor(&r)) + { + runner_compose_down(&r); + return false; + } } if (!runner_apply_formation_settings(&r)) @@ -4023,74 +4246,99 @@ runner_setup(TestSpec *spec, const char *workDir, bool withTmux) if (withTmux) { /* - * Pick the first non-deferred data node as the interactive shell - * target. Falls back to the monitor if no data node is found. + * The bottom tmux pane drops into a shell inside the `pgaftest` + * service container. That service already has: + * - the pgaftest binary on PATH + * - docker + docker compose (DooD via /var/run/docker.sock) + * - /spec.pgaf bind-mounted from the host workDir + * - COMPOSE_PROJECT_NAME, PG_AUTOCTL_MONITOR set + * + * (compose_gen_write emits `sleep infinity` as the command when + * r.interactive is true, so the container stays alive.) */ - const char *shellNode = r.activeMonitorService; - - for (int fi = 0; fi < spec->cluster.formationCount; fi++) - { - const TestFormation *form = &spec->cluster.formations[fi]; - - for (int ni = 0; ni < form->nodeCount; ni++) - { - const TestNode *n = &form->nodes[ni]; - - if (!n->launchDeferred) - { - shellNode = n->name; - fi = spec->cluster.formationCount; /* break outer loop */ - break; - } - } - } /* * Build a three-pane tmux session: * top — docker compose logs -f * middle — pg_autoctl watch on the monitor - * bottom — setup{} block running via `pgaftest _setup_`, then bash + * bottom — setup{} block via `pgaftest _setup_`, then interactive + * shell inside the `pgaftest` service container * - * The setup block runs inside the bottom tmux pane so the user - * immediately gets the session and can watch logs while the cluster - * initialises. When setup completes the pane becomes a bash shell - * in the first data node. + * The bottom pane runs inside the `pgaftest` service container, which + * has the pgaftest binary, docker + docker compose (DooD), /spec.pgaf, + * and COMPOSE_PROJECT_NAME / PG_AUTOCTL_MONITOR already set. + * The user can therefore type e.g.: + * pgaftest step test_002_cut_replication_link + * pgaftest network disconnect node2 + * pgaftest wait until node1 state = wait_primary + */ + + /* + * Four-pane tmux session: + * + * pane 0 (top) docker compose logs -f + * pane 1 pg_autoctl watch --wait + * pane 2 (transient) pgaftest _setup_ — closes naturally when done + * pane 3 (bottom) interactive bash shell via docker compose run * - * pg_autoctl_program holds argv[0] — the path to the pgaftest binary. + * All container commands use `docker compose run --rm` so there is no + * background pgaftest service container to wait for — the containers + * start on demand and have no timing race with tmux pane creation. */ - char bottomCmd[2048]; + + /* pane 2: setup block, or nothing if there is no setup{} section */ + char setupPane[1024] = ""; + if (spec->setup) + { + sformat(setupPane, sizeof(setupPane), + "%s run --rm --name %s-setup setup " + "pgaftest _setup_ /var/lib/postgres/spec.pgaf --work-dir %s", + r.composeBase, r.projectName, workDir); + } + + /* pane 3: interactive shell, always present */ + char shellCmd[512]; + sformat(shellCmd, sizeof(shellCmd), + "%s run --rm -it --name %s-sh setup bash", + r.composeBase, r.projectName); + + log_info("Starting tmux session \"%s\"", r.projectName); + log_info("To open another shell: pgaftest cluster sh"); if (spec->setup) { - sformat(bottomCmd, sizeof(bottomCmd), - "%s _setup_ %s --work-dir %s && " - "%s exec -it %s bash", - pg_autoctl_program, spec->filename, workDir, - r.composeBase, shellNode); + run_cmd( + "tmux new-session -d -s %s " + "\"%s logs -f\" \\; " + "split-window -v " + "\"%s exec %s pg_autoctl watch --wait\" \\; " + "split-window -v " + "\"%s\" \\; " + "split-window -v " + "\"%s\" \\; " + "select-layout even-vertical", + r.projectName, + r.composeBase, + r.composeBase, r.activeMonitorService, + setupPane, + shellCmd); } else { - sformat(bottomCmd, sizeof(bottomCmd), - "%s exec -it %s bash", - r.composeBase, shellNode); + run_cmd( + "tmux new-session -d -s %s " + "\"%s logs -f\" \\; " + "split-window -v " + "\"%s exec %s pg_autoctl watch --wait\" \\; " + "split-window -v " + "\"%s\" \\; " + "select-layout even-vertical", + r.projectName, + r.composeBase, + r.composeBase, r.activeMonitorService, + shellCmd); } - log_info("Starting tmux session \"%s\" (shell target: %s)", - r.projectName, shellNode); - - run_cmd( - "tmux new-session -d -s %s " - "\"%s logs -f\" \\; " - "split-window -v " - "\"%s exec %s pg_autoctl watch\" \\; " - "split-window -v " - "\"%s\" \\; " - "select-layout even-vertical", - r.projectName, - r.composeBase, - r.composeBase, r.activeMonitorService, - bottomCmd); - /* Attach the current terminal into the session. */ run_cmd("tmux attach-session -t %s", r.projectName); } @@ -4124,6 +4372,144 @@ runner_setup(TestSpec *spec, const char *workDir, bool withTmux) } +/* + * runner_state_path — return the path to the state file. + * + * When running inside the pgaftest container (PGAFTEST_IN_CONTAINER is set) + * the state file lives in $HOME so it is always writable by the container user + * regardless of the bind-mount ownership. On the host it lives in workDir + * alongside the generated compose files. + */ +static void +runner_state_path(const char *workDir, char *buf, int buflen) +{ + bool inCompose = getenv("PGAFTEST_IN_CONTAINER") != NULL; /* IGNORE-BANNED */ + + if (inCompose) + { + const char *home = getenv("HOME"); /* IGNORE-BANNED */ + sformat(buf, buflen, "%s/%s", home ? home : "/var/lib/postgres", + PGAFTEST_STATE_FILE); + } + else + { + sformat(buf, buflen, "%s/%s", workDir, PGAFTEST_STATE_FILE); + } +} + + +bool +runner_state_read(const char *workDir, TestRunnerState *st) +{ + memset(st, 0, sizeof(*st)); + st->last_ok = true; /* optimistic default: no step has failed yet */ + + char path[1024]; + runner_state_path(workDir, path, sizeof(path)); + + FILE *f = fopen(path, "r"); /* IGNORE-BANNED */ + if (!f) + { + return false; /* missing is normal before any step runs */ + } + + char buf[4096] = { 0 }; + size_t nr = fread(buf, 1, sizeof(buf) - 1, f); + fclose(f); + + if (nr == 0) + { + return false; + } + + JSON_Value *root = json_parse_string(buf); + if (!root) + { + log_warn("Ignoring corrupt state file \"%s\"", path); + return false; + } + + JSON_Object *obj = json_value_get_object(root); + if (!obj) + { + json_value_free(root); + return false; + } + + st->current = (int) json_object_get_number(obj, "current"); + st->last_ok = json_object_get_boolean(obj, "last_ok") != 0; + + const char *last = json_object_get_string(obj, "last_step"); + if (last) + { + strlcpy(st->last_step, last, sizeof(st->last_step)); + } + + json_value_free(root); + return true; +} + + +bool +runner_state_write(const char *workDir, const TestRunnerState *st) +{ + char path[1024]; + runner_state_path(workDir, path, sizeof(path)); + + JSON_Value *root = json_value_init_object(); + JSON_Object *obj = json_value_get_object(root); + + json_object_set_number(obj, "current", st->current); + json_object_set_boolean(obj, "last_ok", st->last_ok ? 1 : 0); + json_object_set_string(obj, "last_step", st->last_step); + + char *serial = json_serialize_to_string_pretty(root); + json_value_free(root); + + FILE *f = fopen(path, "w"); /* IGNORE-BANNED */ + if (!f) + { + log_error("Cannot write state file \"%s\": %m", path); + free(serial); + return false; + } + + fputs(serial, f); + fputc('\n', f); + fclose(f); + free(serial); + return true; +} + + +bool +runner_step_next(TestSpec *spec, const char *workDir) +{ + TestRunnerState st; + runner_state_read(workDir, &st); + + if (st.current >= spec->sequenceLength) + { + log_info("All %d steps completed", spec->sequenceLength); + return true; + } + + const char *stepName = spec->sequence[st.current]; + bool ok = runner_step(spec, workDir, stepName); + + if (ok) + { + st.current++; + } + + strlcpy(st.last_step, stepName, sizeof(st.last_step)); + st.last_ok = ok; + + (void) runner_state_write(workDir, &st); + return ok; +} + + bool runner_step(TestSpec *spec, const char *workDir, const char *stepName) { @@ -4143,7 +4529,30 @@ runner_step(TestSpec *spec, const char *workDir, const char *stepName) } char err[512] = ""; - if (!runner_exec_step(&r, step, err, sizeof(err), 0)) + bool ok = runner_exec_step(&r, step, err, sizeof(err), 0); + + /* Update interactive state file so `show step` markers stay accurate */ + TestRunnerState st; + runner_state_read(workDir, &st); + strlcpy(st.last_step, stepName, sizeof(st.last_step)); + st.last_ok = ok; + + /* + * When the step matches the one at st.current, advance the cursor so + * `pgaftest step` (no-arg) picks up the next one automatically. + */ + if (st.current < spec->sequenceLength && + strcmp(spec->sequence[st.current], stepName) == 0) + { + if (ok) + { + st.current++; + } + } + + (void) runner_state_write(workDir, &st); + + if (!ok) { log_error("Step \"%s\" failed: %s", stepName, err); return false; @@ -4196,7 +4605,195 @@ runner_down(TestSpec *spec, const char *workDir) runner_exec_step(&r, spec->teardown, err, sizeof(err), 0); } - return runner_compose_down(&r); + bool ok = runner_compose_down(&r); + + /* Kill the tmux session started by `pgaftest tmux`, if it exists. */ + run_cmd("tmux kill-session -t %s 2>/dev/null || true", r.projectName); + + return ok; +} + + +/* + * runner_wait — `pgaftest wait until state = [timeout s]` + * + * Opens a LISTEN connection to the monitor and drives the same notify-goal + * path used by the spec runner. Intended for interactive use from inside the + * pgaftest service container. + */ +bool +runner_wait(TestSpec *spec, const char *workDir, + const char *nodeName, const char *targetState, int timeoutSecs) +{ + TestRunner r; + runner_init(&r, spec, workDir); + + if (!runner_load_state(&r)) + { + return false; + } + + runner_notify_connect(&r); + + if (!runner_wait_notify_goal(&r, nodeName, targetState, + NULL, NULL, 0, timeoutSecs)) + { + log_error("Timeout: %s never reached state %s", nodeName, targetState); + pgsql_finish(&r.notifyConn); + return false; + } + + log_info("%s is now in state %s", nodeName, targetState); + pgsql_finish(&r.notifyConn); + return true; +} + + +/* + * runner_sql — `pgaftest sql ""` + * + * Runs a SQL statement on the named service and prints the result to stdout. + */ +bool +runner_sql(TestSpec *spec, const char *workDir, + const char *service, const char *query) +{ + TestRunner r; + runner_init(&r, spec, workDir); + + if (!runner_load_state(&r)) + { + return false; + } + + char output[4096] = ""; + if (!exec_sql_on_service(&r, service, query, output, sizeof(output))) + { + fformat(stderr, "%s\n", output); + return false; + } + + fformat(stdout, "%s\n", output); + return true; +} + + +/* + * runner_network — `pgaftest network connect|disconnect ` + * + * Wraps docker network connect/disconnect using the project name derived from + * the work dir (or COMPOSE_PROJECT_NAME when running inside the container). + */ +bool +runner_network(TestSpec *spec, const char *workDir, + const char *nodeName, bool connect) +{ + TestRunner r; + runner_init(&r, spec, workDir); + + if (connect) + { + return runner_network_on(&r, nodeName); + } + else + { + return runner_network_off(&r, nodeName); + } +} + + +/* + * runner_assert — `pgaftest assert state = ` + * + * Queries the monitor once; exits 0 if both reportedstate and assignedstate + * equal the target, 1 otherwise. + */ +bool +runner_assert(TestSpec *spec, const char *workDir, + const char *nodeName, const char *targetState) +{ + TestRunner r; + runner_init(&r, spec, workDir); + + if (!runner_load_state(&r)) + { + return false; + } + + char rep[64] = "", asgn[64] = ""; + if (!monitor_get_node_state(&r, nodeName, + rep, sizeof(rep), + asgn, sizeof(asgn))) + { + log_error("Could not query state for node \"%s\"", nodeName); + return false; + } + + if (strcmp(rep, targetState) == 0 && strcmp(asgn, targetState) == 0) + { + log_info("%s: state = %s", nodeName, targetState); + return true; + } + + log_error("%s: expected state %s, got reported=%s assigned=%s", + nodeName, targetState, rep, asgn); + return false; +} + + +bool +runner_show_state(TestSpec *spec, const char *workDir) +{ + TestRunner r; + runner_init(&r, spec, workDir); + + if (!runner_load_state(&r)) + { + return false; + } + + TestRunnerState st; + runner_state_read(workDir, &st); + + if (spec->sequenceLength > 0) + { + if (st.current >= spec->sequenceLength) + { + fformat(stdout, "All %d steps complete\n\n", + spec->sequenceLength); + } + else + { + const char *nextName = spec->sequence[st.current]; + if (!st.last_ok && st.last_step[0]) + { + fformat(stdout, + "Step %d/%d: %s (last run FAILED — will retry)\n\n", + st.current + 1, spec->sequenceLength, nextName); + } + else + { + fformat(stdout, + "Step %d/%d: %s\n\n", + st.current + 1, spec->sequenceLength, nextName); + } + } + } + + char out[8192]; + int rc = run_cmd_capture(out, sizeof(out), + "%s exec -T monitor " + "pg_autoctl show state 2>/dev/null", + r.composeBase); + + if (rc != 0 || out[0] == '\0') + { + log_error("Could not reach monitor — is the cluster running?"); + return false; + } + + fputs(out, stdout); + return true; } @@ -4209,7 +4806,7 @@ runner_show(TestSpec *spec) /* write to stdout instead of a file */ /* No specFile for show — omit the pgaftest service */ bool ok = compose_gen_write(&spec->cluster, "/dev/stdout", - r.projectName, r.contextDir, NULL, r.hostSpecDir); + r.projectName, r.contextDir, NULL, r.hostSpecDir, false); return ok; } @@ -4275,7 +4872,7 @@ runner_prepare(TestSpec *spec, const char *outDir) /* Write docker-compose.yml (with pgaftest service) */ if (!compose_gen_write(&spec->cluster, r.composeFile, r.projectName, r.contextDir, r.specFile, - r.hostSpecDir)) + r.hostSpecDir, false)) { return false; } diff --git a/src/bin/pgaftest/test_runner.h b/src/bin/pgaftest/test_runner.h index fc84bb89b..b3942da4c 100644 --- a/src/bin/pgaftest/test_runner.h +++ b/src/bin/pgaftest/test_runner.h @@ -10,6 +10,7 @@ #define TEST_RUNNER_H #include +#include #include "test_spec.h" #include "pgsql.h" @@ -40,6 +41,7 @@ typedef struct TestRunner char lastSqlService[64]; /* service name of last sql command */ bool composeUp; /* compose stack is running */ + bool interactive; /* --tmux: pgaftest service sleeps instead of running */ /* * Direct libpq connection to the monitor's exposed postgres port. @@ -96,6 +98,43 @@ bool runner_run_setup_only(TestSpec *spec, const char *workDir); */ bool runner_step(TestSpec *spec, const char *workDir, const char *stepName); +/* Print pg_autoctl show state output with step progress header. */ +bool runner_show_state(TestSpec *spec, const char *workDir); + +/* Print a single TestCmd to `f` indented by `indent` spaces. */ +void test_cmd_print(FILE *f, const TestCmd *cmd, int indent); + +/* + * Interactive session state — written to /pgaftest.state after each + * step so that `pgaftest step` (with no argument) can advance automatically. + * + * current index of the NEXT step to run (0 = none run yet) + * last_ok true if the last step succeeded + * + * On failure current stays pointing at the failed step so the default next + * run retries it. + */ +typedef struct TestRunnerState +{ + int current; /* index into sequence[] of next step */ + bool last_ok; /* result of last step, or true if none */ + char last_step[64]; /* name of last step run, or "" */ +} TestRunnerState; + +#define PGAFTEST_STATE_FILE "pgaftest.state" + +/* Read state from /pgaftest.state; returns false and zeroes *st on missing/corrupt file */ +bool runner_state_read(const char *workDir, TestRunnerState *st); + +/* Write state to /pgaftest.state */ +bool runner_state_write(const char *workDir, const TestRunnerState *st); + +/* + * Run the next step (or retry the last failed step). + * Updates the state file on completion. + */ +bool runner_step_next(TestSpec *spec, const char *workDir); + /* * Tear down the compose stack (run teardown{} then compose down). * Used by `pgaftest down`. @@ -107,6 +146,17 @@ bool runner_down(TestSpec *spec, const char *workDir); */ bool runner_show(TestSpec *spec); +/* Interactive sub-commands (DSL mirror, for use inside pgaftest container) */ +bool runner_wait(TestSpec *spec, const char *workDir, + const char *nodeName, const char *targetState, + int timeoutSecs); +bool runner_sql(TestSpec *spec, const char *workDir, + const char *service, const char *query); +bool runner_network(TestSpec *spec, const char *workDir, + const char *nodeName, bool connect); +bool runner_assert(TestSpec *spec, const char *workDir, + const char *nodeName, const char *targetState); + /* * Prepare an output directory with docker-compose.yml, *.ini files, and a * Makefile. Prints the `docker compose up` command to stdout. diff --git a/src/bin/pgaftest/test_spec.h b/src/bin/pgaftest/test_spec.h index bceb2583c..dffea359e 100644 --- a/src/bin/pgaftest/test_spec.h +++ b/src/bin/pgaftest/test_spec.h @@ -73,6 +73,7 @@ typedef struct TestNode char auth[32]; /* per-node auth override; "" = use cluster */ char replicationPassword[256]; /* replication.password written to node ini */ char monitorPassword[256]; /* pg_auto_failover.monitor_password written to node ini */ + char region[64]; /* --region NAME; "" = omit (defaults to "default" on monitor) */ /* Extra Docker named volumes: volume */ struct diff --git a/src/bin/pgaftest/test_spec_parse.c b/src/bin/pgaftest/test_spec_parse.c index f59893f07..77345f8b9 100644 --- a/src/bin/pgaftest/test_spec_parse.c +++ b/src/bin/pgaftest/test_spec_parse.c @@ -107,74 +107,75 @@ T_REPLICATION_PASSWORD = 296, T_EXTENSION_VERSION = 297, T_BIND_SOURCE = 298, - T_FS_INIT = 299, - T_FS_SINGLE = 300, - T_FS_PRIMARY = 301, - T_FS_WAIT_PRIMARY = 302, - T_FS_WAIT_STANDBY = 303, - T_FS_DEMOTED = 304, - T_FS_DEMOTE_TIMEOUT = 305, - T_FS_DRAINING = 306, - T_FS_SECONDARY = 307, - T_FS_CATCHINGUP = 308, - T_FS_PREP_PROMOTION = 309, - T_FS_STOP_REPLICATION = 310, - T_FS_MAINTENANCE = 311, - T_FS_JOIN_PRIMARY = 312, - T_FS_APPLY_SETTINGS = 313, - T_FS_PREPARE_MAINTENANCE = 314, - T_FS_WAIT_MAINTENANCE = 315, - T_FS_REPORT_LSN = 316, - T_FS_FAST_FORWARD = 317, - T_FS_JOIN_SECONDARY = 318, - T_FS_DROPPED = 319, - T_EXEC = 320, - T_EXEC_FAILS = 321, - T_RUN = 322, - T_PG_AUTOCTL = 323, - T_WAIT = 324, - T_UNTIL = 325, - T_TIMEOUT = 326, - T_AND = 327, - T_IS = 328, - T_WITH = 329, - T_ASSERT = 330, - T_SQL = 331, - T_EXPECT = 332, - T_ERROR = 333, - T_PROMOTE = 334, - T_NETWORK = 335, - T_DISCONNECT = 336, - T_CONNECT = 337, - T_SLEEP = 338, - T_COMPOSE = 339, - T_DOWN = 340, - T_START = 341, - T_STOP = 342, - T_STOPPED = 343, - T_KILL = 344, - T_INJECT = 345, - T_STATE = 346, - T_ASSIGNED_STATE = 347, - T_IN = 348, - T_GROUP = 349, - T_LBRACE = 350, - T_RBRACE = 351, - T_COMMA = 352, - T_POSTGRES = 353, - T_STAYS = 354, - T_WHILE = 355, - T_THROUGH = 356, - T_SET = 357, - T_LOGS = 358, - T_NOT = 359, - T_CONTAINS = 360, - T_MATCHES = 361, - T_INTEGER = 362, - T_IDENT = 363, - T_STRING = 364, - T_BLOCK = 365, - T_SHELL_ARGS = 366 + T_REGION = 299, + T_FS_INIT = 300, + T_FS_SINGLE = 301, + T_FS_PRIMARY = 302, + T_FS_WAIT_PRIMARY = 303, + T_FS_WAIT_STANDBY = 304, + T_FS_DEMOTED = 305, + T_FS_DEMOTE_TIMEOUT = 306, + T_FS_DRAINING = 307, + T_FS_SECONDARY = 308, + T_FS_CATCHINGUP = 309, + T_FS_PREP_PROMOTION = 310, + T_FS_STOP_REPLICATION = 311, + T_FS_MAINTENANCE = 312, + T_FS_JOIN_PRIMARY = 313, + T_FS_APPLY_SETTINGS = 314, + T_FS_PREPARE_MAINTENANCE = 315, + T_FS_WAIT_MAINTENANCE = 316, + T_FS_REPORT_LSN = 317, + T_FS_FAST_FORWARD = 318, + T_FS_JOIN_SECONDARY = 319, + T_FS_DROPPED = 320, + T_EXEC = 321, + T_EXEC_FAILS = 322, + T_RUN = 323, + T_PG_AUTOCTL = 324, + T_WAIT = 325, + T_UNTIL = 326, + T_TIMEOUT = 327, + T_AND = 328, + T_IS = 329, + T_WITH = 330, + T_ASSERT = 331, + T_SQL = 332, + T_EXPECT = 333, + T_ERROR = 334, + T_PROMOTE = 335, + T_NETWORK = 336, + T_DISCONNECT = 337, + T_CONNECT = 338, + T_SLEEP = 339, + T_COMPOSE = 340, + T_DOWN = 341, + T_START = 342, + T_STOP = 343, + T_STOPPED = 344, + T_KILL = 345, + T_INJECT = 346, + T_STATE = 347, + T_ASSIGNED_STATE = 348, + T_IN = 349, + T_GROUP = 350, + T_LBRACE = 351, + T_RBRACE = 352, + T_COMMA = 353, + T_POSTGRES = 354, + T_STAYS = 355, + T_WHILE = 356, + T_THROUGH = 357, + T_SET = 358, + T_LOGS = 359, + T_NOT = 360, + T_CONTAINS = 361, + T_MATCHES = 362, + T_INTEGER = 363, + T_IDENT = 364, + T_STRING = 365, + T_BLOCK = 366, + T_SHELL_ARGS = 367 }; #endif /* Tokens. */ @@ -219,80 +220,81 @@ #define T_REPLICATION_PASSWORD 296 #define T_EXTENSION_VERSION 297 #define T_BIND_SOURCE 298 -#define T_FS_INIT 299 -#define T_FS_SINGLE 300 -#define T_FS_PRIMARY 301 -#define T_FS_WAIT_PRIMARY 302 -#define T_FS_WAIT_STANDBY 303 -#define T_FS_DEMOTED 304 -#define T_FS_DEMOTE_TIMEOUT 305 -#define T_FS_DRAINING 306 -#define T_FS_SECONDARY 307 -#define T_FS_CATCHINGUP 308 -#define T_FS_PREP_PROMOTION 309 -#define T_FS_STOP_REPLICATION 310 -#define T_FS_MAINTENANCE 311 -#define T_FS_JOIN_PRIMARY 312 -#define T_FS_APPLY_SETTINGS 313 -#define T_FS_PREPARE_MAINTENANCE 314 -#define T_FS_WAIT_MAINTENANCE 315 -#define T_FS_REPORT_LSN 316 -#define T_FS_FAST_FORWARD 317 -#define T_FS_JOIN_SECONDARY 318 -#define T_FS_DROPPED 319 -#define T_EXEC 320 -#define T_EXEC_FAILS 321 -#define T_RUN 322 -#define T_PG_AUTOCTL 323 -#define T_WAIT 324 -#define T_UNTIL 325 -#define T_TIMEOUT 326 -#define T_AND 327 -#define T_IS 328 -#define T_WITH 329 -#define T_ASSERT 330 -#define T_SQL 331 -#define T_EXPECT 332 -#define T_ERROR 333 -#define T_PROMOTE 334 -#define T_NETWORK 335 -#define T_DISCONNECT 336 -#define T_CONNECT 337 -#define T_SLEEP 338 -#define T_COMPOSE 339 -#define T_DOWN 340 -#define T_START 341 -#define T_STOP 342 -#define T_STOPPED 343 -#define T_KILL 344 -#define T_INJECT 345 -#define T_STATE 346 -#define T_ASSIGNED_STATE 347 -#define T_IN 348 -#define T_GROUP 349 -#define T_LBRACE 350 -#define T_RBRACE 351 -#define T_COMMA 352 -#define T_POSTGRES 353 -#define T_STAYS 354 -#define T_WHILE 355 -#define T_THROUGH 356 -#define T_SET 357 -#define T_LOGS 358 -#define T_NOT 359 -#define T_CONTAINS 360 -#define T_MATCHES 361 -#define T_INTEGER 362 -#define T_IDENT 363 -#define T_STRING 364 -#define T_BLOCK 365 -#define T_SHELL_ARGS 366 +#define T_REGION 299 +#define T_FS_INIT 300 +#define T_FS_SINGLE 301 +#define T_FS_PRIMARY 302 +#define T_FS_WAIT_PRIMARY 303 +#define T_FS_WAIT_STANDBY 304 +#define T_FS_DEMOTED 305 +#define T_FS_DEMOTE_TIMEOUT 306 +#define T_FS_DRAINING 307 +#define T_FS_SECONDARY 308 +#define T_FS_CATCHINGUP 309 +#define T_FS_PREP_PROMOTION 310 +#define T_FS_STOP_REPLICATION 311 +#define T_FS_MAINTENANCE 312 +#define T_FS_JOIN_PRIMARY 313 +#define T_FS_APPLY_SETTINGS 314 +#define T_FS_PREPARE_MAINTENANCE 315 +#define T_FS_WAIT_MAINTENANCE 316 +#define T_FS_REPORT_LSN 317 +#define T_FS_FAST_FORWARD 318 +#define T_FS_JOIN_SECONDARY 319 +#define T_FS_DROPPED 320 +#define T_EXEC 321 +#define T_EXEC_FAILS 322 +#define T_RUN 323 +#define T_PG_AUTOCTL 324 +#define T_WAIT 325 +#define T_UNTIL 326 +#define T_TIMEOUT 327 +#define T_AND 328 +#define T_IS 329 +#define T_WITH 330 +#define T_ASSERT 331 +#define T_SQL 332 +#define T_EXPECT 333 +#define T_ERROR 334 +#define T_PROMOTE 335 +#define T_NETWORK 336 +#define T_DISCONNECT 337 +#define T_CONNECT 338 +#define T_SLEEP 339 +#define T_COMPOSE 340 +#define T_DOWN 341 +#define T_START 342 +#define T_STOP 343 +#define T_STOPPED 344 +#define T_KILL 345 +#define T_INJECT 346 +#define T_STATE 347 +#define T_ASSIGNED_STATE 348 +#define T_IN 349 +#define T_GROUP 350 +#define T_LBRACE 351 +#define T_RBRACE 352 +#define T_COMMA 353 +#define T_POSTGRES 354 +#define T_STAYS 355 +#define T_WHILE 356 +#define T_THROUGH 357 +#define T_SET 358 +#define T_LOGS 359 +#define T_NOT 360 +#define T_CONTAINS 361 +#define T_MATCHES 362 +#define T_INTEGER 363 +#define T_IDENT 364 +#define T_STRING 365 +#define T_BLOCK 366 +#define T_SHELL_ARGS 367 /* Copy the first part of user declarations. */ -#line 1 "test_spec_parse.y" +#line 1 "src/bin/pgaftest/test_spec_parse.y" /* * src/bin/pgaftest/test_spec_parse.y @@ -457,7 +459,7 @@ static TestNode *current_node = NULL; #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -#line 145 "test_spec_parse.y" +#line 145 "src/bin/pgaftest/test_spec_parse.y" { int ival; char *str; @@ -465,7 +467,7 @@ typedef union YYSTYPE TestCmd *cmd; } /* Line 193 of yacc.c. */ -#line 469 "test_spec_parse.c" +#line 471 "src/bin/pgaftest/test_spec_parse.c" YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 @@ -478,7 +480,7 @@ typedef union YYSTYPE /* Line 216 of yacc.c. */ -#line 482 "test_spec_parse.c" +#line 484 "src/bin/pgaftest/test_spec_parse.c" #ifdef short # undef short @@ -693,20 +695,20 @@ union yyalloc /* YYFINAL -- State number of the termination state. */ #define YYFINAL 21 /* YYLAST -- Last index in YYTABLE. */ -#define YYLAST 563 +#define YYLAST 592 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 112 +#define YYNTOKENS 113 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 62 /* YYNRULES -- Number of rules. */ -#define YYNRULES 199 +#define YYNRULES 201 /* YYNRULES -- Number of states. */ -#define YYNSTATES 323 +#define YYNSTATES 326 /* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 366 +#define YYMAXUTOK 367 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -750,7 +752,7 @@ static const yytype_uint8 yytranslate[] = 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95, 96, 97, 98, 99, 100, 101, 102, 103, 104, - 105, 106, 107, 108, 109, 110, 111 + 105, 106, 107, 108, 109, 110, 111, 112 }; #if YYDEBUG @@ -766,85 +768,87 @@ static const yytype_uint16 yyprhs[] = 135, 137, 138, 139, 144, 145, 153, 154, 157, 159, 161, 163, 165, 167, 170, 173, 178, 181, 183, 185, 187, 190, 193, 196, 199, 202, 205, 208, 211, 214, - 217, 220, 223, 227, 231, 234, 237, 241, 245, 246, - 249, 251, 253, 255, 257, 259, 261, 263, 265, 267, - 269, 271, 273, 275, 279, 282, 286, 289, 293, 296, - 300, 303, 305, 307, 309, 314, 319, 321, 325, 326, - 329, 331, 333, 337, 341, 342, 352, 353, 363, 371, - 379, 385, 391, 398, 400, 402, 406, 410, 411, 414, - 417, 422, 423, 426, 430, 437, 444, 451, 458, 462, - 465, 468, 472, 476, 479, 481, 485, 489, 493, 496, - 499, 503, 507, 511, 516, 520, 524, 525, 531, 537, - 541, 546, 552, 557, 563, 566, 567, 570, 572, 574, - 576, 578, 580, 582, 584, 586, 588, 590, 592, 594, - 596, 598, 600, 602, 604, 606, 608, 610, 612, 614 + 217, 220, 223, 226, 229, 233, 237, 240, 243, 247, + 251, 252, 255, 257, 259, 261, 263, 265, 267, 269, + 271, 273, 275, 277, 279, 281, 285, 288, 292, 295, + 299, 302, 306, 309, 311, 313, 315, 320, 325, 327, + 331, 332, 335, 337, 339, 343, 347, 348, 358, 359, + 369, 377, 385, 391, 397, 404, 406, 408, 412, 416, + 417, 420, 423, 428, 429, 432, 436, 443, 450, 457, + 464, 468, 471, 474, 478, 482, 485, 487, 491, 495, + 499, 502, 505, 509, 513, 517, 522, 526, 530, 531, + 537, 543, 547, 552, 558, 563, 569, 572, 573, 576, + 578, 580, 582, 584, 586, 588, 590, 592, 594, 596, + 598, 600, 602, 604, 606, 608, 610, 612, 614, 616, + 618, 620 }; /* YYRHS -- A `-1'-separated list of the rules' RHS. */ static const yytype_int16 yyrhs[] = { - 113, 0, -1, 114, -1, 113, 114, -1, 115, -1, - 137, -1, 138, -1, 139, -1, 170, -1, -1, 3, - 95, 116, 117, 96, -1, -1, 117, 118, -1, 119, - -1, 120, -1, 122, -1, 123, -1, 121, -1, 124, - -1, 43, -1, 4, -1, 4, 39, 108, -1, 4, - 14, 108, -1, 4, 35, 107, -1, 4, 36, 109, - -1, 4, 108, 24, 26, -1, 4, 108, 30, 88, - -1, 4, 108, 24, 26, 36, 109, -1, 13, 109, - -1, 13, 108, -1, 42, 108, -1, 42, 109, -1, - 15, 108, -1, 16, 108, -1, 17, 108, -1, -1, - 18, 125, 126, 95, 129, 96, -1, -1, 126, 128, - -1, 108, -1, 109, -1, 16, -1, 4, -1, 5, - -1, 127, -1, 19, 107, -1, 52, 28, -1, -1, - 129, 132, -1, 108, -1, 4, -1, -1, -1, 130, - 131, 133, 135, -1, -1, 5, 108, 131, 134, 95, - 135, 96, -1, -1, 135, 136, -1, 20, -1, 21, + 114, 0, -1, 115, -1, 114, 115, -1, 116, -1, + 138, -1, 139, -1, 140, -1, 171, -1, -1, 3, + 96, 117, 118, 97, -1, -1, 118, 119, -1, 120, + -1, 121, -1, 123, -1, 124, -1, 122, -1, 125, + -1, 43, -1, 4, -1, 4, 39, 109, -1, 4, + 14, 109, -1, 4, 35, 108, -1, 4, 36, 110, + -1, 4, 109, 24, 26, -1, 4, 109, 30, 89, + -1, 4, 109, 24, 26, 36, 110, -1, 13, 110, + -1, 13, 109, -1, 42, 109, -1, 42, 110, -1, + 15, 109, -1, 16, 109, -1, 17, 109, -1, -1, + 18, 126, 127, 96, 130, 97, -1, -1, 127, 129, + -1, 109, -1, 110, -1, 16, -1, 4, -1, 5, + -1, 128, -1, 19, 108, -1, 53, 28, -1, -1, + 130, 133, -1, 109, -1, 4, -1, -1, -1, 131, + 132, 134, 136, -1, -1, 5, 109, 132, 135, 96, + 136, 97, -1, -1, 136, 137, -1, 20, -1, 21, -1, 22, -1, 23, -1, 26, -1, 24, 26, -1, - 25, 26, -1, 25, 72, 24, 26, -1, 24, 27, - -1, 27, -1, 32, -1, 33, -1, 34, 107, -1, - 94, 107, -1, 35, 107, -1, 38, 108, -1, 39, - 108, -1, 15, 108, -1, 16, 108, -1, 17, 108, - -1, 40, 29, -1, 40, 28, -1, 41, 109, -1, - 37, 109, -1, 31, 108, 108, -1, 31, 108, 109, - -1, 8, 140, -1, 9, 140, -1, 10, 173, 140, - -1, 95, 141, 96, -1, -1, 141, 142, -1, 143, - -1, 149, -1, 156, -1, 157, -1, 158, -1, 159, - -1, 161, -1, 162, -1, 163, -1, 164, -1, 167, - -1, 168, -1, 169, -1, 65, 108, 111, -1, 65, - 108, -1, 66, 108, 111, -1, 66, 108, -1, 67, - 108, 111, -1, 67, 108, -1, 68, 108, 111, -1, - 68, 108, -1, 68, -1, 12, -1, 73, -1, 108, - 91, 144, 172, -1, 108, 91, 144, 108, -1, 145, - -1, 146, 72, 145, -1, -1, 101, 148, -1, 172, - -1, 108, -1, 148, 97, 172, -1, 148, 97, 108, - -1, -1, 69, 70, 108, 91, 144, 172, 150, 147, - 155, -1, -1, 69, 70, 108, 91, 144, 108, 151, - 147, 155, -1, 69, 70, 108, 92, 144, 172, 155, - -1, 69, 70, 108, 92, 144, 108, 155, -1, 69, - 70, 108, 88, 155, -1, 69, 70, 152, 153, 155, - -1, 69, 70, 145, 72, 146, 155, -1, 172, -1, - 108, -1, 152, 97, 172, -1, 152, 97, 108, -1, - -1, 93, 154, -1, 94, 107, -1, 154, 97, 94, - 107, -1, -1, 71, 107, -1, 74, 71, 107, -1, - 75, 108, 91, 144, 172, 155, -1, 75, 108, 91, - 144, 108, 155, -1, 75, 108, 92, 144, 172, 155, - -1, 75, 108, 92, 144, 108, 155, -1, 76, 108, - 110, -1, 77, 110, -1, 77, 78, -1, 77, 78, - 108, -1, 77, 78, 107, -1, 79, 160, -1, 108, - -1, 160, 97, 108, -1, 80, 81, 108, -1, 80, - 82, 108, -1, 83, 107, -1, 84, 85, -1, 84, - 86, 108, -1, 84, 87, 108, -1, 84, 89, 108, - -1, 84, 90, 108, 111, -1, 87, 98, 130, -1, - 86, 98, 130, -1, -1, 100, 166, 95, 141, 96, - -1, 75, 130, 99, 172, 165, -1, 102, 108, 108, - -1, 103, 108, 105, 109, -1, 103, 108, 104, 105, - 109, -1, 103, 108, 106, 109, -1, 103, 108, 104, - 106, 109, -1, 11, 171, -1, -1, 171, 173, -1, - 44, -1, 45, -1, 46, -1, 47, -1, 48, -1, - 49, -1, 50, -1, 51, -1, 52, -1, 53, -1, - 54, -1, 55, -1, 56, -1, 57, -1, 58, -1, - 59, -1, 60, -1, 61, -1, 62, -1, 63, -1, - 64, -1, 108, -1, 109, -1 + 25, 26, -1, 25, 73, 24, 26, -1, 24, 27, + -1, 27, -1, 32, -1, 33, -1, 34, 108, -1, + 44, 109, -1, 44, 110, -1, 95, 108, -1, 35, + 108, -1, 38, 109, -1, 39, 109, -1, 15, 109, + -1, 16, 109, -1, 17, 109, -1, 40, 29, -1, + 40, 28, -1, 41, 110, -1, 37, 110, -1, 31, + 109, 109, -1, 31, 109, 110, -1, 8, 141, -1, + 9, 141, -1, 10, 174, 141, -1, 96, 142, 97, + -1, -1, 142, 143, -1, 144, -1, 150, -1, 157, + -1, 158, -1, 159, -1, 160, -1, 162, -1, 163, + -1, 164, -1, 165, -1, 168, -1, 169, -1, 170, + -1, 66, 109, 112, -1, 66, 109, -1, 67, 109, + 112, -1, 67, 109, -1, 68, 109, 112, -1, 68, + 109, -1, 69, 109, 112, -1, 69, 109, -1, 69, + -1, 12, -1, 74, -1, 109, 92, 145, 173, -1, + 109, 92, 145, 109, -1, 146, -1, 147, 73, 146, + -1, -1, 102, 149, -1, 173, -1, 109, -1, 149, + 98, 173, -1, 149, 98, 109, -1, -1, 70, 71, + 109, 92, 145, 173, 151, 148, 156, -1, -1, 70, + 71, 109, 92, 145, 109, 152, 148, 156, -1, 70, + 71, 109, 93, 145, 173, 156, -1, 70, 71, 109, + 93, 145, 109, 156, -1, 70, 71, 109, 89, 156, + -1, 70, 71, 153, 154, 156, -1, 70, 71, 146, + 73, 147, 156, -1, 173, -1, 109, -1, 153, 98, + 173, -1, 153, 98, 109, -1, -1, 94, 155, -1, + 95, 108, -1, 155, 98, 95, 108, -1, -1, 72, + 108, -1, 75, 72, 108, -1, 76, 109, 92, 145, + 173, 156, -1, 76, 109, 92, 145, 109, 156, -1, + 76, 109, 93, 145, 173, 156, -1, 76, 109, 93, + 145, 109, 156, -1, 77, 109, 111, -1, 78, 111, + -1, 78, 79, -1, 78, 79, 109, -1, 78, 79, + 108, -1, 80, 161, -1, 109, -1, 161, 98, 109, + -1, 81, 82, 109, -1, 81, 83, 109, -1, 84, + 108, -1, 85, 86, -1, 85, 87, 109, -1, 85, + 88, 109, -1, 85, 90, 109, -1, 85, 91, 109, + 112, -1, 88, 99, 131, -1, 87, 99, 131, -1, + -1, 101, 167, 96, 142, 97, -1, 76, 131, 100, + 173, 166, -1, 103, 109, 109, -1, 104, 109, 106, + 110, -1, 104, 109, 105, 106, 110, -1, 104, 109, + 107, 110, -1, 104, 109, 105, 107, 110, -1, 11, + 172, -1, -1, 172, 174, -1, 45, -1, 46, -1, + 47, -1, 48, -1, 49, -1, 50, -1, 51, -1, + 52, -1, 53, -1, 54, -1, 55, -1, 56, -1, + 57, -1, 58, -1, 59, -1, 60, -1, 61, -1, + 62, -1, 63, -1, 64, -1, 65, -1, 109, -1, + 110, -1 }; /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ @@ -857,19 +861,20 @@ static const yytype_uint16 yyrline[] = 412, 413, 414, 415, 419, 424, 428, 434, 436, 455, 456, 465, 482, 481, 489, 488, 496, 498, 502, 507, 512, 516, 520, 526, 531, 535, 540, 544, 548, 552, - 556, 560, 564, 568, 574, 580, 585, 590, 595, 599, - 603, 609, 615, 629, 650, 657, 668, 686, 701, 704, - 712, 713, 714, 715, 716, 717, 718, 719, 720, 721, - 722, 723, 724, 738, 745, 751, 758, 764, 771, 777, - 785, 791, 818, 818, 829, 844, 862, 863, 878, 880, - 884, 892, 900, 907, 919, 918, 930, 929, 940, 949, - 958, 965, 979, 994, 1000, 1007, 1013, 1026, 1028, 1032, - 1037, 1045, 1046, 1047, 1058, 1066, 1074, 1082, 1100, 1115, - 1122, 1126, 1132, 1145, 1153, 1161, 1176, 1182, 1195, 1209, - 1213, 1219, 1225, 1251, 1285, 1291, 1308, 1308, 1313, 1332, - 1357, 1366, 1375, 1384, 1400, 1403, 1405, 1427, 1428, 1429, - 1430, 1431, 1432, 1433, 1434, 1435, 1436, 1437, 1438, 1439, - 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, 1455, 1456 + 556, 560, 565, 570, 574, 578, 584, 590, 595, 600, + 605, 609, 613, 619, 625, 639, 660, 667, 678, 696, + 711, 714, 722, 723, 724, 725, 726, 727, 728, 729, + 730, 731, 732, 733, 734, 748, 755, 761, 768, 774, + 781, 787, 795, 801, 828, 828, 839, 854, 872, 873, + 888, 890, 894, 902, 910, 917, 929, 928, 940, 939, + 950, 959, 968, 975, 989, 1004, 1010, 1017, 1023, 1036, + 1038, 1042, 1047, 1055, 1056, 1057, 1068, 1076, 1084, 1092, + 1110, 1125, 1132, 1136, 1142, 1155, 1163, 1171, 1186, 1192, + 1205, 1219, 1223, 1229, 1235, 1261, 1295, 1301, 1318, 1318, + 1323, 1342, 1367, 1376, 1385, 1394, 1410, 1413, 1415, 1437, + 1438, 1439, 1440, 1441, 1442, 1443, 1444, 1445, 1446, 1447, + 1448, 1449, 1450, 1451, 1452, 1453, 1454, 1455, 1456, 1457, + 1465, 1466 }; #endif @@ -887,9 +892,9 @@ static const char *const yytname[] = "T_VOLUME", "T_LISTEN", "T_CITUS_SECONDARY", "T_CANDIDATE_PRIORITY", "T_PORT", "T_PASSWORD", "T_MONITOR_PASSWORD", "T_CITUS_CLUSTER_NAME", "T_DEBIAN_CLUSTER", "T_REPLICATION_QUORUM", "T_REPLICATION_PASSWORD", - "T_EXTENSION_VERSION", "T_BIND_SOURCE", "T_FS_INIT", "T_FS_SINGLE", - "T_FS_PRIMARY", "T_FS_WAIT_PRIMARY", "T_FS_WAIT_STANDBY", "T_FS_DEMOTED", - "T_FS_DEMOTE_TIMEOUT", "T_FS_DRAINING", "T_FS_SECONDARY", + "T_EXTENSION_VERSION", "T_BIND_SOURCE", "T_REGION", "T_FS_INIT", + "T_FS_SINGLE", "T_FS_PRIMARY", "T_FS_WAIT_PRIMARY", "T_FS_WAIT_STANDBY", + "T_FS_DEMOTED", "T_FS_DEMOTE_TIMEOUT", "T_FS_DRAINING", "T_FS_SECONDARY", "T_FS_CATCHINGUP", "T_FS_PREP_PROMOTION", "T_FS_STOP_REPLICATION", "T_FS_MAINTENANCE", "T_FS_JOIN_PRIMARY", "T_FS_APPLY_SETTINGS", "T_FS_PREPARE_MAINTENANCE", "T_FS_WAIT_MAINTENANCE", "T_FS_REPORT_LSN", @@ -935,33 +940,34 @@ static const yytype_uint16 yytoknum[] = 335, 336, 337, 338, 339, 340, 341, 342, 343, 344, 345, 346, 347, 348, 349, 350, 351, 352, 353, 354, 355, 356, 357, 358, 359, 360, 361, 362, 363, 364, - 365, 366 + 365, 366, 367 }; # endif /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 112, 113, 113, 114, 114, 114, 114, 114, 116, - 115, 117, 117, 118, 118, 118, 118, 118, 118, 118, - 119, 119, 119, 119, 119, 119, 119, 119, 120, 120, - 121, 121, 122, 123, 123, 125, 124, 126, 126, 127, - 127, 127, 127, 127, 128, 128, 128, 129, 129, 130, - 130, 131, 133, 132, 134, 132, 135, 135, 136, 136, - 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, - 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, - 136, 136, 136, 136, 137, 138, 139, 140, 141, 141, - 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, - 142, 142, 142, 143, 143, 143, 143, 143, 143, 143, - 143, 143, 144, 144, 145, 145, 146, 146, 147, 147, - 148, 148, 148, 148, 150, 149, 151, 149, 149, 149, - 149, 149, 149, 152, 152, 152, 152, 153, 153, 154, - 154, 155, 155, 155, 156, 156, 156, 156, 157, 158, - 158, 158, 158, 159, 160, 160, 161, 161, 162, 163, - 163, 163, 163, 163, 164, 164, 166, 165, 167, 168, - 169, 169, 169, 169, 170, 171, 171, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 172, 172, - 172, 172, 172, 172, 172, 172, 172, 172, 173, 173 + 0, 113, 114, 114, 115, 115, 115, 115, 115, 117, + 116, 118, 118, 119, 119, 119, 119, 119, 119, 119, + 120, 120, 120, 120, 120, 120, 120, 120, 121, 121, + 122, 122, 123, 124, 124, 126, 125, 127, 127, 128, + 128, 128, 128, 128, 129, 129, 129, 130, 130, 131, + 131, 132, 134, 133, 135, 133, 136, 136, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 137, 137, 137, 137, + 137, 137, 137, 137, 137, 137, 138, 139, 140, 141, + 142, 142, 143, 143, 143, 143, 143, 143, 143, 143, + 143, 143, 143, 143, 143, 144, 144, 144, 144, 144, + 144, 144, 144, 144, 145, 145, 146, 146, 147, 147, + 148, 148, 149, 149, 149, 149, 151, 150, 152, 150, + 150, 150, 150, 150, 150, 153, 153, 153, 153, 154, + 154, 155, 155, 156, 156, 156, 157, 157, 157, 157, + 158, 159, 159, 159, 159, 160, 161, 161, 162, 162, + 163, 164, 164, 164, 164, 164, 165, 165, 167, 166, + 168, 169, 170, 170, 170, 170, 171, 172, 172, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 173, 173, 173, 173, 173, 173, 173, 173, 173, 173, + 174, 174 }; /* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ @@ -975,18 +981,19 @@ static const yytype_uint8 yyr2[] = 1, 0, 0, 4, 0, 7, 0, 2, 1, 1, 1, 1, 1, 2, 2, 4, 2, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, 2, 3, 3, 2, 2, 3, 3, 0, 2, + 2, 2, 2, 2, 3, 3, 2, 2, 3, 3, + 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 3, 2, 3, 2, 3, + 2, 3, 2, 1, 1, 1, 4, 4, 1, 3, + 0, 2, 1, 1, 3, 3, 0, 9, 0, 9, + 7, 7, 5, 5, 6, 1, 1, 3, 3, 0, + 2, 2, 4, 0, 2, 3, 6, 6, 6, 6, + 3, 2, 2, 3, 3, 2, 1, 3, 3, 3, + 2, 2, 3, 3, 3, 4, 3, 3, 0, 5, + 5, 3, 4, 5, 4, 5, 2, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 3, 2, 3, 2, 3, 2, 3, - 2, 1, 1, 1, 4, 4, 1, 3, 0, 2, - 1, 1, 3, 3, 0, 9, 0, 9, 7, 7, - 5, 5, 6, 1, 1, 3, 3, 0, 2, 2, - 4, 0, 2, 3, 6, 6, 6, 6, 3, 2, - 2, 3, 3, 2, 1, 3, 3, 3, 2, 2, - 3, 3, 3, 4, 3, 3, 0, 5, 5, 3, - 4, 5, 4, 5, 2, 0, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + 1, 1 }; /* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state @@ -994,39 +1001,39 @@ static const yytype_uint8 yyr2[] = means the default is an error. */ static const yytype_uint8 yydefact[] = { - 0, 0, 0, 0, 0, 175, 0, 2, 4, 5, - 6, 7, 8, 9, 88, 84, 85, 198, 199, 0, - 174, 1, 3, 11, 0, 86, 176, 0, 0, 0, - 0, 111, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 87, 0, 0, 89, 90, 91, 92, 93, - 94, 95, 96, 97, 98, 99, 100, 101, 102, 20, + 0, 0, 0, 0, 0, 177, 0, 2, 4, 5, + 6, 7, 8, 9, 90, 86, 87, 200, 201, 0, + 176, 1, 3, 11, 0, 88, 178, 0, 0, 0, + 0, 113, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 89, 0, 0, 91, 92, 93, 94, 95, + 96, 97, 98, 99, 100, 101, 102, 103, 104, 20, 0, 0, 0, 0, 35, 0, 19, 10, 12, 13, - 14, 17, 15, 16, 18, 104, 106, 108, 110, 0, - 50, 49, 0, 0, 150, 149, 154, 153, 0, 0, - 158, 159, 0, 0, 0, 0, 0, 0, 0, 0, + 14, 17, 15, 16, 18, 106, 108, 110, 112, 0, + 50, 49, 0, 0, 152, 151, 156, 155, 0, 0, + 160, 161, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 29, 28, 32, 33, 34, - 37, 30, 31, 103, 105, 107, 109, 177, 178, 179, - 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, - 190, 191, 192, 193, 194, 195, 196, 197, 134, 0, - 137, 133, 0, 0, 0, 148, 152, 151, 0, 156, - 157, 160, 161, 162, 0, 49, 165, 164, 169, 0, - 0, 0, 22, 23, 24, 21, 0, 0, 0, 141, - 0, 0, 0, 0, 0, 141, 112, 113, 0, 0, - 0, 155, 163, 0, 0, 170, 172, 25, 26, 42, + 37, 30, 31, 105, 107, 109, 111, 179, 180, 181, + 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, + 192, 193, 194, 195, 196, 197, 198, 199, 136, 0, + 139, 135, 0, 0, 0, 150, 154, 153, 0, 158, + 159, 162, 163, 164, 0, 49, 167, 166, 171, 0, + 0, 0, 22, 23, 24, 21, 0, 0, 0, 143, + 0, 0, 0, 0, 0, 143, 114, 115, 0, 0, + 0, 157, 165, 0, 0, 172, 174, 25, 26, 42, 43, 41, 0, 0, 47, 39, 40, 44, 38, 0, - 0, 130, 0, 0, 0, 116, 141, 0, 138, 136, - 135, 131, 141, 141, 141, 141, 166, 168, 171, 173, - 0, 45, 46, 0, 142, 0, 126, 124, 141, 141, - 0, 0, 132, 139, 0, 145, 144, 147, 146, 0, - 27, 0, 36, 51, 48, 143, 118, 118, 129, 128, - 0, 117, 0, 88, 51, 52, 0, 141, 141, 115, - 114, 140, 0, 54, 56, 121, 119, 120, 127, 125, - 167, 0, 53, 0, 56, 0, 0, 0, 58, 59, + 0, 132, 0, 0, 0, 118, 143, 0, 140, 138, + 137, 133, 143, 143, 143, 143, 168, 170, 173, 175, + 0, 45, 46, 0, 144, 0, 128, 126, 143, 143, + 0, 0, 134, 141, 0, 147, 146, 149, 148, 0, + 27, 0, 36, 51, 48, 145, 120, 120, 131, 130, + 0, 119, 0, 90, 51, 52, 0, 143, 143, 117, + 116, 142, 0, 54, 56, 123, 121, 122, 129, 127, + 169, 0, 53, 0, 56, 0, 0, 0, 58, 59, 60, 61, 0, 0, 62, 67, 0, 68, 69, 0, - 0, 0, 0, 0, 0, 0, 0, 57, 123, 122, - 0, 75, 76, 77, 63, 66, 64, 0, 0, 70, - 72, 81, 73, 74, 79, 78, 80, 71, 55, 0, - 82, 83, 65 + 0, 0, 0, 0, 0, 0, 0, 0, 57, 125, + 124, 0, 77, 78, 79, 63, 66, 64, 0, 0, + 70, 74, 83, 75, 76, 81, 80, 82, 71, 72, + 73, 55, 0, 84, 85, 65 }; /* YYDEFGOTO[NTERM-NUM]. */ @@ -1034,7 +1041,7 @@ static const yytype_int16 yydefgoto[] = { -1, 6, 7, 8, 23, 27, 68, 69, 70, 71, 72, 73, 74, 110, 168, 197, 198, 223, 82, 255, - 244, 264, 271, 272, 297, 9, 10, 11, 15, 24, + 244, 264, 271, 272, 298, 9, 10, 11, 15, 24, 45, 46, 178, 139, 206, 257, 266, 47, 247, 246, 140, 175, 208, 201, 48, 49, 50, 51, 87, 52, 53, 54, 55, 217, 239, 56, 57, 58, 12, 20, @@ -1043,220 +1050,226 @@ static const yytype_int16 yydefgoto[] = /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing STATE-NUM. */ -#define YYPACT_NINF -160 +#define YYPACT_NINF -157 static const yytype_int16 yypact[] = { - 70, -66, -64, -64, -54, -160, 53, -160, -160, -160, - -160, -160, -160, -160, -160, -160, -160, -160, -160, -64, - -54, -160, -160, -160, 396, -160, -160, 4, -58, -51, - -26, -19, 16, 3, -10, -62, 2, 6, 11, -20, - 40, 41, -160, 32, 38, -160, -160, -160, -160, -160, - -160, -160, -160, -160, -160, -160, -160, -160, -160, -3, - -16, 47, 48, 57, -160, -13, -160, -160, -160, -160, - -160, -160, -160, -160, -160, 55, 56, 62, 89, 135, - -160, 10, 102, 92, -4, -160, -160, 106, 97, 120, - -160, -160, 121, 122, 124, 125, 5, 5, 126, -21, - 127, 129, 128, 130, 14, -160, -160, -160, -160, -160, - -160, -160, -160, -160, -160, -160, -160, -160, -160, -160, - -160, -160, -160, -160, -160, -160, -160, -160, -160, -160, - -160, -160, -160, -160, -160, -160, -160, -160, -65, 167, - -69, -160, -2, -2, 499, -160, -160, -160, 132, -160, - -160, -160, -160, -160, 131, -160, -160, -160, -160, 9, - 156, 157, -160, -160, -160, -160, 215, 179, -1, -22, - -2, -2, 160, 175, 163, -22, -160, -160, 200, 228, - 170, -160, -160, 184, 185, -160, -160, 259, -160, -160, - -160, -160, 189, 269, -160, -160, -160, -160, -160, 191, - 229, -160, 265, 293, 208, -160, -29, 194, 205, -160, - -160, -160, -22, -22, -22, -22, -160, -160, -160, -160, - 195, -160, -160, 1, -160, 196, 233, 234, -22, -22, - -2, 160, -160, -160, 213, -160, -160, -160, -160, 235, - -160, 223, -160, -160, -160, -160, 231, 231, -160, -160, - 330, -160, 226, -160, -160, -160, 358, -22, -22, -160, - -160, -160, 439, -160, -160, -160, 237, -160, -160, -160, - -160, 240, 137, 395, -160, 250, 251, 252, -160, -160, - -160, -160, 90, -12, -160, -160, 253, -160, -160, 255, - 256, 257, 260, 261, 93, 258, 263, -160, -160, -160, - 110, -160, -160, -160, -160, -160, -160, 340, 15, -160, - -160, -160, -160, -160, -160, -160, -160, -160, -160, 339, - -160, -160, -160 + 58, -79, -43, -43, -54, -157, 74, -157, -157, -157, + -157, -157, -157, -157, -157, -157, -157, -157, -157, -43, + -54, -157, -157, -157, 424, -157, -157, 6, -52, -44, + -17, 10, 36, 4, 15, -68, 31, -20, 38, 3, + -11, 12, -157, 43, 44, -157, -157, -157, -157, -157, + -157, -157, -157, -157, -157, -157, -157, -157, -157, -7, + -31, 49, 50, 59, -157, -29, -157, -157, -157, -157, + -157, -157, -157, -157, -157, 57, 64, 70, 71, 163, + -157, 8, 85, 75, -12, -157, -157, 72, 78, 79, + -157, -157, 80, 81, 82, 83, 5, 5, 84, -80, + 86, 88, 87, 89, 7, -157, -157, -157, -157, -157, + -157, -157, -157, -157, -157, -157, -157, -157, -157, -157, + -157, -157, -157, -157, -157, -157, -157, -157, -157, -157, + -157, -157, -157, -157, -157, -157, -157, -157, -51, 121, + -48, -157, 2, 2, 527, -157, -157, -157, 90, -157, + -157, -157, -157, -157, 94, -157, -157, -157, -157, -2, + 93, 119, -157, -157, -157, -157, 174, 112, -1, -21, + 2, 2, 95, 107, 191, -21, -157, -157, 228, 256, + 129, -157, -157, 122, 123, -157, -157, 195, -157, -157, + -157, -157, 126, 229, -157, -157, -157, -157, -157, 150, + 187, -157, 293, 321, 168, -157, -28, 153, 164, -157, + -157, -157, -21, -21, -21, -21, -157, -157, -157, -157, + 154, -157, -157, 1, -157, 155, 192, 193, -21, -21, + 2, 95, -157, -157, 172, -157, -157, -157, -157, 173, + -157, 159, -157, -157, -157, -157, 169, 169, -157, -157, + 358, -157, 162, -157, -157, -157, 386, -21, -21, -157, + -157, -157, 467, -157, -157, -157, 196, -157, -157, -157, + -157, 199, 140, 423, -157, 188, 189, 190, -157, -157, + -157, -157, 91, -13, -157, -157, 213, -157, -157, 215, + 216, 186, 217, 218, 92, 219, 13, 220, -157, -157, + -157, 110, -157, -157, -157, -157, -157, -157, 301, 29, + -157, -157, -157, -157, -157, -157, -157, -157, -157, -157, + -157, -157, 304, -157, -157, -157 }; /* YYPGOTO[NTERM-NUM]. */ static const yytype_int16 yypgoto[] = { - -160, -160, 365, -160, -160, -160, -160, -160, -160, -160, - -160, -160, -160, -160, -160, -160, -160, -160, -95, 118, - -160, -160, -160, 123, -160, -160, -160, -160, 22, 142, - -160, -160, -131, -159, -160, 149, -160, -160, -160, -160, - -160, -160, -160, -138, -160, -160, -160, -160, -160, -160, - -160, -160, -160, -160, -160, -160, -160, -160, -160, -160, - -144, 378 + -157, -157, 325, -157, -157, -157, -157, -157, -157, -157, + -157, -157, -157, -157, -157, -157, -157, -157, -95, 105, + -157, -157, -157, 60, -157, -157, -157, -157, 17, 108, + -157, -157, -131, -156, -157, 113, -157, -157, -157, -157, + -157, -157, -157, -142, -157, -157, -157, -157, -157, -157, + -157, -157, -157, -157, -157, -157, -157, -157, -157, -157, + -144, 312 }; /* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If positive, shift that token. If negative, reduce the rule which number is the opposite. If zero, do what YYDEFACT says. If YYTABLE_NINF, syntax error. */ -#define YYTABLE_NINF -116 +#define YYTABLE_NINF -118 static const yytype_int16 yytable[] = { - 180, 156, 157, 189, 190, 80, 241, 80, 59, 80, - 176, 100, 179, 205, 306, 191, 84, 60, 192, 61, - 62, 63, 64, 169, 173, 16, 170, 171, 174, 13, - 210, 14, 101, 102, 213, 215, 103, 211, 166, 202, - 203, 25, 199, 231, 167, 200, 65, 66, 85, 199, - 75, 193, 200, 21, 17, 18, 1, 76, 227, 229, - 307, 2, 3, 4, 5, 91, 92, 93, 232, 94, - 95, 177, 251, 1, 235, 236, 237, 238, 2, 3, - 4, 5, 77, 159, 160, 161, 79, 88, 89, 78, - 248, 249, 105, 106, 194, 111, 112, 242, 83, 250, - 67, 142, 143, 146, 147, 104, 260, 195, 196, 155, - 86, 81, 267, 155, 183, 184, 304, 305, 90, 268, - 269, 314, 315, 320, 321, 275, 276, 277, 243, 299, - 278, 279, 280, 281, 282, 283, 284, 285, 96, 97, - 98, 286, 287, 288, 289, 290, 99, 291, 292, 293, - 294, 295, 275, 276, 277, 107, 108, 278, 279, 280, - 281, 282, 283, 284, 285, 109, 113, 114, 286, 287, - 288, 289, 290, 115, 291, 292, 293, 294, 295, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 116, 144, 145, 148, 296, 149, 318, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 150, 151, - 152, 296, 153, 154, 158, 162, 163, 164, 165, 172, - 181, 187, 182, 138, 117, 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, - 133, 134, 135, 136, 137, 185, 186, 188, 204, 207, - 216, 209, 117, 118, 119, 120, 121, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 218, 219, 220, 221, 222, 224, 230, - 225, 233, 234, 245, 240, -115, -114, 252, 212, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 253, 254, 256, 261, 273, 274, 214, 117, 118, 119, - 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, - 130, 131, 132, 133, 134, 135, 136, 137, 301, 302, - 303, 308, 309, 310, 319, 322, 311, 316, 312, 313, - 317, 22, 263, 226, 117, 118, 119, 120, 121, 122, - 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, - 133, 134, 135, 136, 137, 262, 258, 300, 26, 0, - 0, 228, 117, 118, 119, 120, 121, 122, 123, 124, - 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, - 135, 136, 137, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 259, 117, - 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, - 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, - 0, 28, 29, 30, 31, 32, 265, 0, 0, 0, - 0, 33, 34, 35, 0, 36, 37, 0, 0, 38, - 39, 0, 40, 41, 0, 0, 0, 0, 0, 0, - 0, 0, 42, 0, 0, 0, 0, 0, 43, 44, - 0, 0, 0, 298, 28, 29, 30, 31, 32, 0, - 0, 0, 0, 0, 33, 34, 35, 0, 36, 37, - 0, 0, 38, 39, 0, 40, 41, 0, 0, 0, - 0, 0, 0, 0, 0, 270, 0, 0, 0, 0, - 0, 43, 44, 117, 118, 119, 120, 121, 122, 123, + 180, 156, 157, 189, 190, 80, 241, 100, 80, 80, + 59, 84, 179, 307, 176, 191, 205, 13, 192, 60, + 16, 61, 62, 63, 64, 159, 160, 161, 101, 102, + 210, 166, 103, 211, 213, 215, 25, 167, 169, 202, + 203, 170, 171, 85, 199, 231, 173, 200, 65, 66, + 174, 199, 193, 14, 200, 17, 18, 75, 227, 229, + 308, 1, 88, 89, 232, 76, 2, 3, 4, 5, + 235, 236, 237, 238, 21, 251, 177, 1, 105, 106, + 111, 112, 2, 3, 4, 5, 248, 249, 96, 91, + 92, 93, 77, 94, 95, 194, 146, 147, 242, 250, + 142, 143, 104, 67, 183, 184, 260, 79, 195, 196, + 155, 97, 267, 81, 155, 268, 269, 305, 306, 78, + 315, 316, 318, 319, 83, 275, 276, 277, 243, 300, + 278, 279, 280, 281, 282, 283, 284, 285, 323, 324, + 86, 286, 287, 288, 289, 290, 90, 291, 292, 293, + 294, 295, 98, 99, 296, 275, 276, 277, 107, 108, + 278, 279, 280, 281, 282, 283, 284, 285, 109, 113, + 148, 286, 287, 288, 289, 290, 114, 291, 292, 293, + 294, 295, 115, 116, 296, 144, 145, 149, 150, 151, + 152, 153, 154, 158, 172, 162, 163, 164, 165, 181, + 187, 188, 207, 185, 204, 297, 182, 321, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 186, + 216, 220, 218, 219, 221, 297, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 222, 224, 225, + 230, 233, 234, 245, 240, -117, -116, 252, 254, 253, + 261, 256, 138, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, - 134, 135, 136, 137 + 134, 135, 136, 137, 273, 274, 312, 302, 303, 304, + 209, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 309, 310, 311, 322, 313, 314, 320, 317, + 325, 22, 26, 0, 301, 0, 0, 212, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 263, + 258, 262, 0, 0, 0, 214, 117, 118, 119, 120, + 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, + 131, 132, 133, 134, 135, 136, 137, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 226, 117, 118, 119, 120, 121, 122, 123, + 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, + 134, 135, 136, 137, 0, 0, 0, 0, 0, 0, + 228, 117, 118, 119, 120, 121, 122, 123, 124, 125, + 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, + 136, 137, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 259, 117, 118, + 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, + 129, 130, 131, 132, 133, 134, 135, 136, 137, 0, + 28, 29, 30, 31, 32, 265, 0, 0, 0, 0, + 33, 34, 35, 0, 36, 37, 0, 0, 38, 39, + 0, 40, 41, 0, 0, 0, 0, 0, 0, 0, + 0, 42, 0, 0, 0, 0, 0, 43, 44, 0, + 0, 0, 299, 28, 29, 30, 31, 32, 0, 0, + 0, 0, 0, 33, 34, 35, 0, 36, 37, 0, + 0, 38, 39, 0, 40, 41, 0, 0, 0, 0, + 0, 0, 0, 0, 270, 0, 0, 0, 0, 0, + 43, 44, 117, 118, 119, 120, 121, 122, 123, 124, + 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, + 135, 136, 137 }; static const yytype_int16 yycheck[] = { - 144, 96, 97, 4, 5, 4, 5, 4, 4, 4, - 12, 14, 143, 172, 26, 16, 78, 13, 19, 15, - 16, 17, 18, 88, 93, 3, 91, 92, 97, 95, - 174, 95, 35, 36, 178, 179, 39, 175, 24, 170, - 171, 19, 71, 72, 30, 74, 42, 43, 110, 71, - 108, 52, 74, 0, 108, 109, 3, 108, 202, 203, - 72, 8, 9, 10, 11, 85, 86, 87, 206, 89, - 90, 73, 231, 3, 212, 213, 214, 215, 8, 9, - 10, 11, 108, 104, 105, 106, 70, 81, 82, 108, - 228, 229, 108, 109, 95, 108, 109, 96, 108, 230, - 96, 91, 92, 107, 108, 108, 250, 108, 109, 108, - 108, 108, 256, 108, 105, 106, 26, 27, 107, 257, - 258, 28, 29, 108, 109, 15, 16, 17, 223, 273, - 20, 21, 22, 23, 24, 25, 26, 27, 98, 98, - 108, 31, 32, 33, 34, 35, 108, 37, 38, 39, - 40, 41, 15, 16, 17, 108, 108, 20, 21, 22, - 23, 24, 25, 26, 27, 108, 111, 111, 31, 32, - 33, 34, 35, 111, 37, 38, 39, 40, 41, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 111, 99, 110, 97, 94, 108, 96, 44, 45, 46, + 144, 96, 97, 4, 5, 4, 5, 14, 4, 4, + 4, 79, 143, 26, 12, 16, 172, 96, 19, 13, + 3, 15, 16, 17, 18, 105, 106, 107, 35, 36, + 174, 24, 39, 175, 178, 179, 19, 30, 89, 170, + 171, 92, 93, 111, 72, 73, 94, 75, 42, 43, + 98, 72, 53, 96, 75, 109, 110, 109, 202, 203, + 73, 3, 82, 83, 206, 109, 8, 9, 10, 11, + 212, 213, 214, 215, 0, 231, 74, 3, 109, 110, + 109, 110, 8, 9, 10, 11, 228, 229, 99, 86, + 87, 88, 109, 90, 91, 96, 108, 109, 97, 230, + 92, 93, 109, 97, 106, 107, 250, 71, 109, 110, + 109, 99, 256, 109, 109, 257, 258, 26, 27, 109, + 28, 29, 109, 110, 109, 15, 16, 17, 223, 273, + 20, 21, 22, 23, 24, 25, 26, 27, 109, 110, + 109, 31, 32, 33, 34, 35, 108, 37, 38, 39, + 40, 41, 109, 109, 44, 15, 16, 17, 109, 109, + 20, 21, 22, 23, 24, 25, 26, 27, 109, 112, + 98, 31, 32, 33, 34, 35, 112, 37, 38, 39, + 40, 41, 112, 112, 44, 100, 111, 109, 109, 109, + 109, 109, 109, 109, 73, 109, 108, 110, 109, 109, + 26, 89, 95, 110, 109, 95, 112, 97, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 108, 108, - 108, 94, 108, 108, 108, 108, 107, 109, 108, 72, - 108, 26, 111, 108, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 109, 109, 88, 108, 94, - 100, 108, 44, 45, 46, 47, 48, 49, 50, 51, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 110, + 101, 36, 110, 110, 108, 95, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, 28, 108, 72, + 92, 108, 98, 108, 110, 73, 73, 95, 109, 96, + 108, 102, 109, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, 109, 109, 36, 107, 28, 107, 91, - 71, 107, 97, 107, 109, 72, 72, 94, 108, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - 95, 108, 101, 107, 97, 95, 108, 44, 45, 46, + 62, 63, 64, 65, 98, 96, 110, 109, 109, 109, + 109, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, 109, 108, 108, 24, 109, 109, 108, 110, + 26, 6, 20, -1, 274, -1, -1, 109, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 108, 108, - 108, 108, 107, 107, 24, 26, 109, 109, 108, 108, - 107, 6, 254, 108, 44, 45, 46, 47, 48, 49, - 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, - 60, 61, 62, 63, 64, 253, 247, 274, 20, -1, - -1, 108, 44, 45, 46, 47, 48, 49, 50, 51, + 57, 58, 59, 60, 61, 62, 63, 64, 65, 254, + 247, 253, -1, -1, -1, 109, 45, 46, 47, 48, + 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, + 59, 60, 61, 62, 63, 64, 65, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, 109, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, - 62, 63, 64, -1, -1, -1, -1, -1, -1, -1, - -1, -1, -1, -1, -1, -1, -1, -1, 108, 44, - 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, - 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, - -1, 65, 66, 67, 68, 69, 108, -1, -1, -1, - -1, 75, 76, 77, -1, 79, 80, -1, -1, 83, - 84, -1, 86, 87, -1, -1, -1, -1, -1, -1, - -1, -1, 96, -1, -1, -1, -1, -1, 102, 103, - -1, -1, -1, 108, 65, 66, 67, 68, 69, -1, - -1, -1, -1, -1, 75, 76, 77, -1, 79, 80, - -1, -1, 83, 84, -1, 86, 87, -1, -1, -1, - -1, -1, -1, -1, -1, 96, -1, -1, -1, -1, - -1, 102, 103, 44, 45, 46, 47, 48, 49, 50, - 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, - 61, 62, 63, 64 + 62, 63, 64, 65, -1, -1, -1, -1, -1, -1, + 109, 45, 46, 47, 48, 49, 50, 51, 52, 53, + 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, + 64, 65, -1, -1, -1, -1, -1, -1, -1, -1, + -1, -1, -1, -1, -1, -1, -1, 109, 45, 46, + 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, + 57, 58, 59, 60, 61, 62, 63, 64, 65, -1, + 66, 67, 68, 69, 70, 109, -1, -1, -1, -1, + 76, 77, 78, -1, 80, 81, -1, -1, 84, 85, + -1, 87, 88, -1, -1, -1, -1, -1, -1, -1, + -1, 97, -1, -1, -1, -1, -1, 103, 104, -1, + -1, -1, 109, 66, 67, 68, 69, 70, -1, -1, + -1, -1, -1, 76, 77, 78, -1, 80, 81, -1, + -1, 84, 85, -1, 87, 88, -1, -1, -1, -1, + -1, -1, -1, -1, 97, -1, -1, -1, -1, -1, + 103, 104, 45, 46, 47, 48, 49, 50, 51, 52, + 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, + 63, 64, 65 }; /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 3, 8, 9, 10, 11, 113, 114, 115, 137, - 138, 139, 170, 95, 95, 140, 140, 108, 109, 173, - 171, 0, 114, 116, 141, 140, 173, 117, 65, 66, - 67, 68, 69, 75, 76, 77, 79, 80, 83, 84, - 86, 87, 96, 102, 103, 142, 143, 149, 156, 157, - 158, 159, 161, 162, 163, 164, 167, 168, 169, 4, - 13, 15, 16, 17, 18, 42, 43, 96, 118, 119, - 120, 121, 122, 123, 124, 108, 108, 108, 108, 70, - 4, 108, 130, 108, 78, 110, 108, 160, 81, 82, - 107, 85, 86, 87, 89, 90, 98, 98, 108, 108, - 14, 35, 36, 39, 108, 108, 109, 108, 108, 108, - 125, 108, 109, 111, 111, 111, 111, 44, 45, 46, - 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, - 57, 58, 59, 60, 61, 62, 63, 64, 108, 145, - 152, 172, 91, 92, 99, 110, 107, 108, 97, 108, - 108, 108, 108, 108, 108, 108, 130, 130, 108, 104, - 105, 106, 108, 107, 109, 108, 24, 30, 126, 88, - 91, 92, 72, 93, 97, 153, 12, 73, 144, 144, - 172, 108, 111, 105, 106, 109, 109, 26, 88, 4, - 5, 16, 19, 52, 95, 108, 109, 127, 128, 71, - 74, 155, 144, 144, 108, 145, 146, 94, 154, 108, - 172, 155, 108, 172, 108, 172, 100, 165, 109, 109, - 36, 107, 28, 129, 107, 71, 108, 172, 108, 172, - 91, 72, 155, 107, 97, 155, 155, 155, 155, 166, - 109, 5, 96, 130, 132, 107, 151, 150, 155, 155, - 144, 145, 94, 95, 108, 131, 101, 147, 147, 108, - 172, 107, 141, 131, 133, 108, 148, 172, 155, 155, - 96, 134, 135, 97, 95, 15, 16, 17, 20, 21, + 0, 3, 8, 9, 10, 11, 114, 115, 116, 138, + 139, 140, 171, 96, 96, 141, 141, 109, 110, 174, + 172, 0, 115, 117, 142, 141, 174, 118, 66, 67, + 68, 69, 70, 76, 77, 78, 80, 81, 84, 85, + 87, 88, 97, 103, 104, 143, 144, 150, 157, 158, + 159, 160, 162, 163, 164, 165, 168, 169, 170, 4, + 13, 15, 16, 17, 18, 42, 43, 97, 119, 120, + 121, 122, 123, 124, 125, 109, 109, 109, 109, 71, + 4, 109, 131, 109, 79, 111, 109, 161, 82, 83, + 108, 86, 87, 88, 90, 91, 99, 99, 109, 109, + 14, 35, 36, 39, 109, 109, 110, 109, 109, 109, + 126, 109, 110, 112, 112, 112, 112, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, + 58, 59, 60, 61, 62, 63, 64, 65, 109, 146, + 153, 173, 92, 93, 100, 111, 108, 109, 98, 109, + 109, 109, 109, 109, 109, 109, 131, 131, 109, 105, + 106, 107, 109, 108, 110, 109, 24, 30, 127, 89, + 92, 93, 73, 94, 98, 154, 12, 74, 145, 145, + 173, 109, 112, 106, 107, 110, 110, 26, 89, 4, + 5, 16, 19, 53, 96, 109, 110, 128, 129, 72, + 75, 156, 145, 145, 109, 146, 147, 95, 155, 109, + 173, 156, 109, 173, 109, 173, 101, 166, 110, 110, + 36, 108, 28, 130, 108, 72, 109, 173, 109, 173, + 92, 73, 156, 108, 98, 156, 156, 156, 156, 167, + 110, 5, 97, 131, 133, 108, 152, 151, 156, 156, + 145, 146, 95, 96, 109, 132, 102, 148, 148, 109, + 173, 108, 142, 132, 134, 109, 149, 173, 156, 156, + 97, 135, 136, 98, 96, 15, 16, 17, 20, 21, 22, 23, 24, 25, 26, 27, 31, 32, 33, 34, - 35, 37, 38, 39, 40, 41, 94, 136, 108, 172, - 135, 108, 108, 108, 26, 27, 26, 72, 108, 107, - 107, 109, 108, 108, 28, 29, 109, 107, 96, 24, - 108, 109, 26 + 35, 37, 38, 39, 40, 41, 44, 95, 137, 109, + 173, 136, 109, 109, 109, 26, 27, 26, 73, 109, + 108, 108, 110, 109, 109, 28, 29, 110, 109, 110, + 108, 97, 24, 109, 110, 26 }; #define yyerrok (yyerrstatus = 0) @@ -2071,7 +2084,7 @@ yyparse () switch (yyn) { case 9: -#line 233 "test_spec_parse.y" +#line 233 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_spec->cluster.ssl, "self-signed", sizeof(current_spec->cluster.ssl)); @@ -2081,19 +2094,19 @@ yyparse () break; case 19: -#line 254 "test_spec_parse.y" +#line 254 "src/bin/pgaftest/test_spec_parse.y" { current_spec->cluster.bindSource = true; ;} break; case 20: -#line 268 "test_spec_parse.y" +#line 268 "src/bin/pgaftest/test_spec_parse.y" { current_spec->cluster.withMonitor = true; ;} break; case 21: -#line 272 "test_spec_parse.y" +#line 272 "src/bin/pgaftest/test_spec_parse.y" { current_spec->cluster.withMonitor = true; strlcpy(current_spec->cluster.monitorDebianCluster, (yyvsp[(3) - (3)].str), @@ -2103,7 +2116,7 @@ yyparse () break; case 22: -#line 279 "test_spec_parse.y" +#line 279 "src/bin/pgaftest/test_spec_parse.y" { current_spec->cluster.withMonitor = true; strlcpy(current_spec->cluster.monitorImageTarget, (yyvsp[(3) - (3)].str), @@ -2113,7 +2126,7 @@ yyparse () break; case 23: -#line 286 "test_spec_parse.y" +#line 286 "src/bin/pgaftest/test_spec_parse.y" { current_spec->cluster.withMonitor = true; /* monitor port not stored in TestCluster yet; ignore */ @@ -2122,7 +2135,7 @@ yyparse () break; case 24: -#line 292 "test_spec_parse.y" +#line 292 "src/bin/pgaftest/test_spec_parse.y" { current_spec->cluster.withMonitor = true; strlcpy(current_spec->cluster.monitorPassword, (yyvsp[(3) - (3)].str), @@ -2132,7 +2145,7 @@ yyparse () break; case 25: -#line 299 "test_spec_parse.y" +#line 299 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_spec->cluster.secondMonitorName, (yyvsp[(2) - (4)].str), sizeof(current_spec->cluster.secondMonitorName)); @@ -2142,7 +2155,7 @@ yyparse () break; case 26: -#line 306 "test_spec_parse.y" +#line 306 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_spec->cluster.secondMonitorName, (yyvsp[(2) - (4)].str), sizeof(current_spec->cluster.secondMonitorName)); @@ -2152,7 +2165,7 @@ yyparse () break; case 27: -#line 313 "test_spec_parse.y" +#line 313 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_spec->cluster.secondMonitorName, (yyvsp[(2) - (6)].str), sizeof(current_spec->cluster.secondMonitorName)); @@ -2164,7 +2177,7 @@ yyparse () break; case 28: -#line 326 "test_spec_parse.y" +#line 326 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_spec->cluster.image, (yyvsp[(2) - (2)].str), sizeof(current_spec->cluster.image)); @@ -2173,7 +2186,7 @@ yyparse () break; case 29: -#line 332 "test_spec_parse.y" +#line 332 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_spec->cluster.image, (yyvsp[(2) - (2)].str), sizeof(current_spec->cluster.image)); @@ -2182,7 +2195,7 @@ yyparse () break; case 30: -#line 342 "test_spec_parse.y" +#line 342 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_spec->cluster.extensionVersion, (yyvsp[(2) - (2)].str), sizeof(current_spec->cluster.extensionVersion)); @@ -2191,7 +2204,7 @@ yyparse () break; case 31: -#line 348 "test_spec_parse.y" +#line 348 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_spec->cluster.extensionVersion, (yyvsp[(2) - (2)].str), sizeof(current_spec->cluster.extensionVersion)); @@ -2200,7 +2213,7 @@ yyparse () break; case 32: -#line 358 "test_spec_parse.y" +#line 358 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_spec->cluster.ssl, (yyvsp[(2) - (2)].str), sizeof(current_spec->cluster.ssl)); @@ -2209,7 +2222,7 @@ yyparse () break; case 33: -#line 368 "test_spec_parse.y" +#line 368 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_spec->cluster.auth, (yyvsp[(2) - (2)].str), sizeof(current_spec->cluster.auth)); @@ -2218,7 +2231,7 @@ yyparse () break; case 34: -#line 374 "test_spec_parse.y" +#line 374 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_spec->cluster.auth, (yyvsp[(2) - (2)].str), sizeof(current_spec->cluster.auth)); @@ -2227,7 +2240,7 @@ yyparse () break; case 35: -#line 384 "test_spec_parse.y" +#line 384 "src/bin/pgaftest/test_spec_parse.y" { TestCluster *cl = ¤t_spec->cluster; if (cl->formationCount >= PGAF_MAX_FORMATIONS) @@ -2244,32 +2257,32 @@ yyparse () break; case 39: -#line 411 "test_spec_parse.y" +#line 411 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 40: -#line 412 "test_spec_parse.y" +#line 412 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 41: -#line 413 "test_spec_parse.y" +#line 413 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = strdup("auth"); ;} break; case 42: -#line 414 "test_spec_parse.y" +#line 414 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = strdup("monitor"); ;} break; case 43: -#line 415 "test_spec_parse.y" +#line 415 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = strdup("node"); ;} break; case 44: -#line 420 "test_spec_parse.y" +#line 420 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_formation->name, (yyvsp[(1) - (1)].str), sizeof(current_formation->name)); free((yyvsp[(1) - (1)].str)); @@ -2277,31 +2290,31 @@ yyparse () break; case 45: -#line 425 "test_spec_parse.y" +#line 425 "src/bin/pgaftest/test_spec_parse.y" { current_formation->numSync = (yyvsp[(2) - (2)].ival); ;} break; case 46: -#line 429 "test_spec_parse.y" +#line 429 "src/bin/pgaftest/test_spec_parse.y" { current_formation->disableSecondary = true; ;} break; case 49: -#line 455 "test_spec_parse.y" +#line 455 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; case 50: -#line 456 "test_spec_parse.y" +#line 456 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = strdup("monitor"); ;} break; case 51: -#line 465 "test_spec_parse.y" +#line 465 "src/bin/pgaftest/test_spec_parse.y" { if (current_formation->nodeCount >= PGAF_MAX_NODES) { @@ -2317,7 +2330,7 @@ yyparse () break; case 52: -#line 482 "test_spec_parse.y" +#line 482 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_node->name, (yyvsp[(1) - (2)].str), sizeof(current_node->name)); free((yyvsp[(1) - (2)].str)); @@ -2325,7 +2338,7 @@ yyparse () break; case 54: -#line 489 "test_spec_parse.y" +#line 489 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_node->name, (yyvsp[(2) - (3)].str), sizeof(current_node->name)); free((yyvsp[(2) - (3)].str)); @@ -2333,7 +2346,7 @@ yyparse () break; case 58: -#line 503 "test_spec_parse.y" +#line 503 "src/bin/pgaftest/test_spec_parse.y" { current_node->kind = NODE_KIND_CITUS_COORDINATOR; current_spec->cluster.withCitus = true; @@ -2341,7 +2354,7 @@ yyparse () break; case 59: -#line 508 "test_spec_parse.y" +#line 508 "src/bin/pgaftest/test_spec_parse.y" { current_node->kind = NODE_KIND_CITUS_WORKER; current_spec->cluster.withCitus = true; @@ -2349,21 +2362,21 @@ yyparse () break; case 60: -#line 513 "test_spec_parse.y" +#line 513 "src/bin/pgaftest/test_spec_parse.y" { current_node->replicationQuorum = false; ;} break; case 61: -#line 517 "test_spec_parse.y" +#line 517 "src/bin/pgaftest/test_spec_parse.y" { current_node->noMonitor = true; ;} break; case 62: -#line 521 "test_spec_parse.y" +#line 521 "src/bin/pgaftest/test_spec_parse.y" { /* bare "deferred" = create and launch deferred (both gates) */ current_node->createDeferred = true; @@ -2372,7 +2385,7 @@ yyparse () break; case 63: -#line 527 "test_spec_parse.y" +#line 527 "src/bin/pgaftest/test_spec_parse.y" { /* "launch deferred" alone = run-deferred only, create immediate */ current_node->launchDeferred = true; @@ -2380,14 +2393,14 @@ yyparse () break; case 64: -#line 532 "test_spec_parse.y" +#line 532 "src/bin/pgaftest/test_spec_parse.y" { current_node->createDeferred = true; ;} break; case 65: -#line 536 "test_spec_parse.y" +#line 536 "src/bin/pgaftest/test_spec_parse.y" { current_node->createDeferred = true; current_node->launchDeferred = true; @@ -2395,56 +2408,72 @@ yyparse () break; case 66: -#line 541 "test_spec_parse.y" +#line 541 "src/bin/pgaftest/test_spec_parse.y" { current_node->launchDeferred = false; ;} break; case 67: -#line 545 "test_spec_parse.y" +#line 545 "src/bin/pgaftest/test_spec_parse.y" { current_node->launchDeferred = false; ;} break; case 68: -#line 549 "test_spec_parse.y" +#line 549 "src/bin/pgaftest/test_spec_parse.y" { current_node->listen = true; ;} break; case 69: -#line 553 "test_spec_parse.y" +#line 553 "src/bin/pgaftest/test_spec_parse.y" { current_node->citusSecondary = true; ;} break; case 70: -#line 557 "test_spec_parse.y" +#line 557 "src/bin/pgaftest/test_spec_parse.y" { current_node->candidatePriority = (yyvsp[(2) - (2)].ival); ;} break; case 71: -#line 561 "test_spec_parse.y" +#line 561 "src/bin/pgaftest/test_spec_parse.y" { - current_node->group = (yyvsp[(2) - (2)].ival); + strlcpy(current_node->region, (yyvsp[(2) - (2)].str), sizeof(current_node->region)); + free((yyvsp[(2) - (2)].str)); ;} break; case 72: -#line 565 "test_spec_parse.y" +#line 566 "src/bin/pgaftest/test_spec_parse.y" { - current_node->pgPort = (yyvsp[(2) - (2)].ival); + strlcpy(current_node->region, (yyvsp[(2) - (2)].str), sizeof(current_node->region)); + free((yyvsp[(2) - (2)].str)); ;} break; case 73: -#line 569 "test_spec_parse.y" +#line 571 "src/bin/pgaftest/test_spec_parse.y" + { + current_node->group = (yyvsp[(2) - (2)].ival); + ;} + break; + + case 74: +#line 575 "src/bin/pgaftest/test_spec_parse.y" + { + current_node->pgPort = (yyvsp[(2) - (2)].ival); + ;} + break; + + case 75: +#line 579 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_node->citusClusterName, (yyvsp[(2) - (2)].str), sizeof(current_node->citusClusterName)); @@ -2452,8 +2481,8 @@ yyparse () ;} break; - case 74: -#line 575 "test_spec_parse.y" + case 76: +#line 585 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_node->debianCluster, (yyvsp[(2) - (2)].str), sizeof(current_node->debianCluster)); @@ -2461,46 +2490,46 @@ yyparse () ;} break; - case 75: -#line 581 "test_spec_parse.y" + case 77: +#line 591 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_node->ssl, (yyvsp[(2) - (2)].str), sizeof(current_node->ssl)); free((yyvsp[(2) - (2)].str)); ;} break; - case 76: -#line 586 "test_spec_parse.y" + case 78: +#line 596 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_node->auth, (yyvsp[(2) - (2)].str), sizeof(current_node->auth)); free((yyvsp[(2) - (2)].str)); ;} break; - case 77: -#line 591 "test_spec_parse.y" + case 79: +#line 601 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_node->auth, (yyvsp[(2) - (2)].str), sizeof(current_node->auth)); free((yyvsp[(2) - (2)].str)); ;} break; - case 78: -#line 596 "test_spec_parse.y" + case 80: +#line 606 "src/bin/pgaftest/test_spec_parse.y" { current_node->replicationQuorum = true; ;} break; - case 79: -#line 600 "test_spec_parse.y" + case 81: +#line 610 "src/bin/pgaftest/test_spec_parse.y" { current_node->replicationQuorum = false; ;} break; - case 80: -#line 604 "test_spec_parse.y" + case 82: +#line 614 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_node->replicationPassword, (yyvsp[(2) - (2)].str), sizeof(current_node->replicationPassword)); @@ -2508,8 +2537,8 @@ yyparse () ;} break; - case 81: -#line 610 "test_spec_parse.y" + case 83: +#line 620 "src/bin/pgaftest/test_spec_parse.y" { strlcpy(current_node->monitorPassword, (yyvsp[(2) - (2)].str), sizeof(current_node->monitorPassword)); @@ -2517,8 +2546,8 @@ yyparse () ;} break; - case 82: -#line 616 "test_spec_parse.y" + case 84: +#line 626 "src/bin/pgaftest/test_spec_parse.y" { /* volume — adds a named Docker volume */ int vi = current_node->volumeCount; @@ -2534,8 +2563,8 @@ yyparse () ;} break; - case 83: -#line 630 "test_spec_parse.y" + case 85: +#line 640 "src/bin/pgaftest/test_spec_parse.y" { /* volume "/path/with spaces" */ int vi = current_node->volumeCount; @@ -2551,22 +2580,22 @@ yyparse () ;} break; - case 84: -#line 651 "test_spec_parse.y" + case 86: +#line 661 "src/bin/pgaftest/test_spec_parse.y" { current_spec->setup = (yyvsp[(2) - (2)].step); ;} break; - case 85: -#line 658 "test_spec_parse.y" + case 87: +#line 668 "src/bin/pgaftest/test_spec_parse.y" { current_spec->teardown = (yyvsp[(2) - (2)].step); ;} break; - case 86: -#line 669 "test_spec_parse.y" + case 88: +#line 679 "src/bin/pgaftest/test_spec_parse.y" { TestStep *s = (yyvsp[(3) - (3)].step); strncpy(s->name, (yyvsp[(2) - (3)].str), sizeof(s->name) - 1); @@ -2575,8 +2604,8 @@ yyparse () ;} break; - case 87: -#line 687 "test_spec_parse.y" + case 89: +#line 697 "src/bin/pgaftest/test_spec_parse.y" { /* post-process: CMD_SQL immediately before CMD_EXPECT_ERROR */ for (TestCmd *c = (yyvsp[(2) - (3)].step)->commands; c; c = c->next) @@ -2589,88 +2618,88 @@ yyparse () ;} break; - case 88: -#line 701 "test_spec_parse.y" + case 90: +#line 711 "src/bin/pgaftest/test_spec_parse.y" { (yyval.step) = make_step(""); ;} break; - case 89: -#line 705 "test_spec_parse.y" + case 91: +#line 715 "src/bin/pgaftest/test_spec_parse.y" { if ((yyvsp[(2) - (2)].cmd)) append_cmd((yyvsp[(1) - (2)].step), (yyvsp[(2) - (2)].cmd)); (yyval.step) = (yyvsp[(1) - (2)].step); ;} break; - case 90: -#line 712 "test_spec_parse.y" - { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} - break; - - case 91: -#line 713 "test_spec_parse.y" - { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} - break; - case 92: -#line 714 "test_spec_parse.y" +#line 722 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} break; case 93: -#line 715 "test_spec_parse.y" +#line 723 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} break; case 94: -#line 716 "test_spec_parse.y" +#line 724 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} break; case 95: -#line 717 "test_spec_parse.y" +#line 725 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} break; case 96: -#line 718 "test_spec_parse.y" +#line 726 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} break; case 97: -#line 719 "test_spec_parse.y" +#line 727 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} break; case 98: -#line 720 "test_spec_parse.y" +#line 728 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} break; case 99: -#line 721 "test_spec_parse.y" +#line 729 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} break; case 100: -#line 722 "test_spec_parse.y" +#line 730 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} break; case 101: -#line 723 "test_spec_parse.y" +#line 731 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} break; case 102: -#line 724 "test_spec_parse.y" +#line 732 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} break; case 103: -#line 739 "test_spec_parse.y" +#line 733 "src/bin/pgaftest/test_spec_parse.y" + { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} + break; + + case 104: +#line 734 "src/bin/pgaftest/test_spec_parse.y" + { (yyval.cmd) = (yyvsp[(1) - (1)].cmd); ;} + break; + + case 105: +#line 749 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_EXEC); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (3)].str), sizeof((yyval.cmd)->service)); @@ -2679,8 +2708,8 @@ yyparse () ;} break; - case 104: -#line 746 "test_spec_parse.y" + case 106: +#line 756 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_EXEC); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (2)].str), sizeof((yyval.cmd)->service)); @@ -2688,8 +2717,8 @@ yyparse () ;} break; - case 105: -#line 752 "test_spec_parse.y" + case 107: +#line 762 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_EXEC_FAILS); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (3)].str), sizeof((yyval.cmd)->service)); @@ -2698,8 +2727,8 @@ yyparse () ;} break; - case 106: -#line 759 "test_spec_parse.y" + case 108: +#line 769 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_EXEC_FAILS); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (2)].str), sizeof((yyval.cmd)->service)); @@ -2707,8 +2736,8 @@ yyparse () ;} break; - case 107: -#line 765 "test_spec_parse.y" + case 109: +#line 775 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_RUN); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (3)].str), sizeof((yyval.cmd)->service)); @@ -2717,8 +2746,8 @@ yyparse () ;} break; - case 108: -#line 772 "test_spec_parse.y" + case 110: +#line 782 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_RUN); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (2)].str), sizeof((yyval.cmd)->service)); @@ -2726,8 +2755,8 @@ yyparse () ;} break; - case 109: -#line 778 "test_spec_parse.y" + case 111: +#line 788 "src/bin/pgaftest/test_spec_parse.y" { /* "pg_autoctl perform failover --formation auth" * EXEC_ARGS returns T_IDENT for first word, T_SHELL_ARGS for rest */ @@ -2737,8 +2766,8 @@ yyparse () ;} break; - case 110: -#line 786 "test_spec_parse.y" + case 112: +#line 796 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_PG_AUTOCTL); strlcpy((yyval.cmd)->args, (yyvsp[(2) - (2)].str), sizeof((yyval.cmd)->args)); @@ -2746,15 +2775,15 @@ yyparse () ;} break; - case 111: -#line 792 "test_spec_parse.y" + case 113: +#line 802 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_PG_AUTOCTL); ;} break; - case 114: -#line 830 "test_spec_parse.y" + case 116: +#line 840 "src/bin/pgaftest/test_spec_parse.y" { if (!current_wait_cmd) current_wait_cmd = make_cmd(CMD_WAIT_MULTI); @@ -2771,8 +2800,8 @@ yyparse () ;} break; - case 115: -#line 845 "test_spec_parse.y" + case 117: +#line 855 "src/bin/pgaftest/test_spec_parse.y" { if (!current_wait_cmd) current_wait_cmd = make_cmd(CMD_WAIT_MULTI); @@ -2789,8 +2818,8 @@ yyparse () ;} break; - case 120: -#line 885 "test_spec_parse.y" + case 122: +#line 895 "src/bin/pgaftest/test_spec_parse.y" { /* current_pass_cmd set by the enclosing wait_cmd rule */ if (current_pass_cmd && @@ -2800,8 +2829,8 @@ yyparse () ;} break; - case 121: -#line 893 "test_spec_parse.y" + case 123: +#line 903 "src/bin/pgaftest/test_spec_parse.y" { if (current_pass_cmd && current_pass_cmd->passThroughCount < PGAF_MAX_WAIT_STATES) @@ -2811,8 +2840,8 @@ yyparse () ;} break; - case 122: -#line 901 "test_spec_parse.y" + case 124: +#line 911 "src/bin/pgaftest/test_spec_parse.y" { if (current_pass_cmd && current_pass_cmd->passThroughCount < PGAF_MAX_WAIT_STATES) @@ -2821,8 +2850,8 @@ yyparse () ;} break; - case 123: -#line 908 "test_spec_parse.y" + case 125: +#line 918 "src/bin/pgaftest/test_spec_parse.y" { if (current_pass_cmd && current_pass_cmd->passThroughCount < PGAF_MAX_WAIT_STATES) @@ -2832,16 +2861,16 @@ yyparse () ;} break; - case 124: -#line 919 "test_spec_parse.y" + case 126: +#line 929 "src/bin/pgaftest/test_spec_parse.y" { current_pass_cmd = make_cmd(CMD_WAIT_STATE); strlcpy(current_pass_cmd->service, (yyvsp[(3) - (6)].str), sizeof(current_pass_cmd->service)); strlcpy(current_pass_cmd->state, (yyvsp[(6) - (6)].str), sizeof(current_pass_cmd->state)); free((yyvsp[(3) - (6)].str)); ;} break; - case 125: -#line 924 "test_spec_parse.y" + case 127: +#line 934 "src/bin/pgaftest/test_spec_parse.y" { current_pass_cmd->timeoutSeconds = (yyvsp[(9) - (9)].ival); (yyval.cmd) = current_pass_cmd; @@ -2849,16 +2878,16 @@ yyparse () ;} break; - case 126: -#line 930 "test_spec_parse.y" + case 128: +#line 940 "src/bin/pgaftest/test_spec_parse.y" { current_pass_cmd = make_cmd(CMD_WAIT_STATE); strlcpy(current_pass_cmd->service, (yyvsp[(3) - (6)].str), sizeof(current_pass_cmd->service)); strlcpy(current_pass_cmd->state, (yyvsp[(6) - (6)].str), sizeof(current_pass_cmd->state)); free((yyvsp[(3) - (6)].str)); free((yyvsp[(6) - (6)].str)); ;} break; - case 127: -#line 935 "test_spec_parse.y" + case 129: +#line 945 "src/bin/pgaftest/test_spec_parse.y" { current_pass_cmd->timeoutSeconds = (yyvsp[(9) - (9)].ival); (yyval.cmd) = current_pass_cmd; @@ -2866,8 +2895,8 @@ yyparse () ;} break; - case 128: -#line 941 "test_spec_parse.y" + case 130: +#line 951 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_WAIT_STATE); (yyval.cmd)->kind = CMD_ASSERT_ASSIGNED; @@ -2878,8 +2907,8 @@ yyparse () ;} break; - case 129: -#line 950 "test_spec_parse.y" + case 131: +#line 960 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_WAIT_STATE); (yyval.cmd)->kind = CMD_ASSERT_ASSIGNED; @@ -2890,8 +2919,8 @@ yyparse () ;} break; - case 130: -#line 959 "test_spec_parse.y" + case 132: +#line 969 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_WAIT_STOPPED); strlcpy((yyval.cmd)->service, (yyvsp[(3) - (5)].str), sizeof((yyval.cmd)->service)); @@ -2900,8 +2929,8 @@ yyparse () ;} break; - case 131: -#line 966 "test_spec_parse.y" + case 133: +#line 976 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = current_wait_cmd; (yyval.cmd)->timeoutSeconds = (yyvsp[(5) - (5)].ival); @@ -2909,8 +2938,8 @@ yyparse () ;} break; - case 132: -#line 980 "test_spec_parse.y" + case 134: +#line 990 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = current_wait_cmd; (yyval.cmd)->timeoutSeconds = (yyvsp[(6) - (6)].ival); @@ -2918,8 +2947,8 @@ yyparse () ;} break; - case 133: -#line 995 "test_spec_parse.y" + case 135: +#line 1005 "src/bin/pgaftest/test_spec_parse.y" { current_wait_cmd = make_cmd(CMD_WAIT_STATES); strlcpy(current_wait_cmd->waitStates[current_wait_cmd->waitStateCount++], @@ -2927,8 +2956,8 @@ yyparse () ;} break; - case 134: -#line 1001 "test_spec_parse.y" + case 136: +#line 1011 "src/bin/pgaftest/test_spec_parse.y" { current_wait_cmd = make_cmd(CMD_WAIT_STATES); strlcpy(current_wait_cmd->waitStates[current_wait_cmd->waitStateCount++], @@ -2937,8 +2966,8 @@ yyparse () ;} break; - case 135: -#line 1008 "test_spec_parse.y" + case 137: +#line 1018 "src/bin/pgaftest/test_spec_parse.y" { if (current_wait_cmd->waitStateCount < PGAF_MAX_WAIT_STATES) strlcpy(current_wait_cmd->waitStates[current_wait_cmd->waitStateCount++], @@ -2946,8 +2975,8 @@ yyparse () ;} break; - case 136: -#line 1014 "test_spec_parse.y" + case 138: +#line 1024 "src/bin/pgaftest/test_spec_parse.y" { if (current_wait_cmd->waitStateCount < PGAF_MAX_WAIT_STATES) strlcpy(current_wait_cmd->waitStates[current_wait_cmd->waitStateCount++], @@ -2956,39 +2985,39 @@ yyparse () ;} break; - case 139: -#line 1033 "test_spec_parse.y" + case 141: +#line 1043 "src/bin/pgaftest/test_spec_parse.y" { if (current_wait_cmd->waitGroupCount < PGAF_MAX_WAIT_GROUPS) current_wait_cmd->waitGroups[current_wait_cmd->waitGroupCount++] = (yyvsp[(2) - (2)].ival); ;} break; - case 140: -#line 1038 "test_spec_parse.y" + case 142: +#line 1048 "src/bin/pgaftest/test_spec_parse.y" { if (current_wait_cmd->waitGroupCount < PGAF_MAX_WAIT_GROUPS) current_wait_cmd->waitGroups[current_wait_cmd->waitGroupCount++] = (yyvsp[(4) - (4)].ival); ;} break; - case 141: -#line 1045 "test_spec_parse.y" + case 143: +#line 1055 "src/bin/pgaftest/test_spec_parse.y" { (yyval.ival) = PGAF_TIMEOUT_DEFAULT; ;} break; - case 142: -#line 1046 "test_spec_parse.y" + case 144: +#line 1056 "src/bin/pgaftest/test_spec_parse.y" { (yyval.ival) = (yyvsp[(2) - (2)].ival); ;} break; - case 143: -#line 1047 "test_spec_parse.y" + case 145: +#line 1057 "src/bin/pgaftest/test_spec_parse.y" { (yyval.ival) = (yyvsp[(3) - (3)].ival); ;} break; - case 144: -#line 1059 "test_spec_parse.y" + case 146: +#line 1069 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd((yyvsp[(6) - (6)].ival) > 0 ? CMD_WAIT_STATE : CMD_ASSERT_STATE); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (6)].str), sizeof((yyval.cmd)->service)); @@ -2998,8 +3027,8 @@ yyparse () ;} break; - case 145: -#line 1067 "test_spec_parse.y" + case 147: +#line 1077 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd((yyvsp[(6) - (6)].ival) > 0 ? CMD_WAIT_STATE : CMD_ASSERT_STATE); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (6)].str), sizeof((yyval.cmd)->service)); @@ -3009,8 +3038,8 @@ yyparse () ;} break; - case 146: -#line 1075 "test_spec_parse.y" + case 148: +#line 1085 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_ASSERT_ASSIGNED); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (6)].str), sizeof((yyval.cmd)->service)); @@ -3020,8 +3049,8 @@ yyparse () ;} break; - case 147: -#line 1083 "test_spec_parse.y" + case 149: +#line 1093 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_ASSERT_ASSIGNED); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (6)].str), sizeof((yyval.cmd)->service)); @@ -3031,8 +3060,8 @@ yyparse () ;} break; - case 148: -#line 1101 "test_spec_parse.y" + case 150: +#line 1111 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_SQL); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (3)].str), sizeof((yyval.cmd)->service)); @@ -3041,8 +3070,8 @@ yyparse () ;} break; - case 149: -#line 1116 "test_spec_parse.y" + case 151: +#line 1126 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_EXPECT); strlcpy((yyval.cmd)->expected, (yyvsp[(2) - (2)].str), sizeof((yyval.cmd)->expected)); @@ -3051,15 +3080,15 @@ yyparse () ;} break; - case 150: -#line 1123 "test_spec_parse.y" + case 152: +#line 1133 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_EXPECT_ERROR); ;} break; - case 151: -#line 1127 "test_spec_parse.y" + case 153: +#line 1137 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_EXPECT_ERROR); strlcpy((yyval.cmd)->state, (yyvsp[(3) - (3)].str), sizeof((yyval.cmd)->state)); @@ -3067,8 +3096,8 @@ yyparse () ;} break; - case 152: -#line 1133 "test_spec_parse.y" + case 154: +#line 1143 "src/bin/pgaftest/test_spec_parse.y" { /* SQLSTATE codes like 25006 are all digits, lexed as T_INTEGER */ (yyval.cmd) = make_cmd(CMD_EXPECT_ERROR); @@ -3076,16 +3105,16 @@ yyparse () ;} break; - case 153: -#line 1146 "test_spec_parse.y" + case 155: +#line 1156 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = current_promote_cmd; current_promote_cmd = NULL; ;} break; - case 154: -#line 1154 "test_spec_parse.y" + case 156: +#line 1164 "src/bin/pgaftest/test_spec_parse.y" { current_promote_cmd = make_cmd(CMD_PROMOTE); current_promote_cmd->timeoutSeconds = PGAF_TIMEOUT_DEFAULT; @@ -3095,8 +3124,8 @@ yyparse () ;} break; - case 155: -#line 1162 "test_spec_parse.y" + case 157: +#line 1172 "src/bin/pgaftest/test_spec_parse.y" { if (current_promote_cmd->promoteCount < PGAF_MAX_PROMOTE_NODES) strlcpy(current_promote_cmd->promoteNodes[current_promote_cmd->promoteCount++], @@ -3105,8 +3134,8 @@ yyparse () ;} break; - case 156: -#line 1177 "test_spec_parse.y" + case 158: +#line 1187 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_NETWORK_OFF); strlcpy((yyval.cmd)->service, (yyvsp[(3) - (3)].str), sizeof((yyval.cmd)->service)); @@ -3114,8 +3143,8 @@ yyparse () ;} break; - case 157: -#line 1183 "test_spec_parse.y" + case 159: +#line 1193 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_NETWORK_ON); strlcpy((yyval.cmd)->service, (yyvsp[(3) - (3)].str), sizeof((yyval.cmd)->service)); @@ -3123,23 +3152,23 @@ yyparse () ;} break; - case 158: -#line 1196 "test_spec_parse.y" + case 160: +#line 1206 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_SLEEP); (yyval.cmd)->timeoutSeconds = (yyvsp[(2) - (2)].ival); ;} break; - case 159: -#line 1210 "test_spec_parse.y" + case 161: +#line 1220 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_COMPOSE_DOWN); ;} break; - case 160: -#line 1214 "test_spec_parse.y" + case 162: +#line 1224 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_COMPOSE_START); strlcpy((yyval.cmd)->service, (yyvsp[(3) - (3)].str), sizeof((yyval.cmd)->service)); @@ -3147,8 +3176,8 @@ yyparse () ;} break; - case 161: -#line 1220 "test_spec_parse.y" + case 163: +#line 1230 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_COMPOSE_STOP); strlcpy((yyval.cmd)->service, (yyvsp[(3) - (3)].str), sizeof((yyval.cmd)->service)); @@ -3156,8 +3185,8 @@ yyparse () ;} break; - case 162: -#line 1226 "test_spec_parse.y" + case 164: +#line 1236 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_COMPOSE_KILL); strlcpy((yyval.cmd)->service, (yyvsp[(3) - (3)].str), sizeof((yyval.cmd)->service)); @@ -3165,8 +3194,8 @@ yyparse () ;} break; - case 163: -#line 1252 "test_spec_parse.y" + case 165: +#line 1262 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_COMPOSE_INJECT); strlcpy((yyval.cmd)->expected, (yyvsp[(3) - (4)].str), sizeof((yyval.cmd)->expected)); /* image */ @@ -3191,8 +3220,8 @@ yyparse () ;} break; - case 164: -#line 1286 "test_spec_parse.y" + case 166: +#line 1296 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_STOP_POSTGRES); strlcpy((yyval.cmd)->service, (yyvsp[(3) - (3)].str), sizeof((yyval.cmd)->service)); @@ -3200,8 +3229,8 @@ yyparse () ;} break; - case 165: -#line 1292 "test_spec_parse.y" + case 167: +#line 1302 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_START_POSTGRES); strlcpy((yyval.cmd)->service, (yyvsp[(3) - (3)].str), sizeof((yyval.cmd)->service)); @@ -3209,18 +3238,18 @@ yyparse () ;} break; - case 166: -#line 1308 "test_spec_parse.y" + case 168: +#line 1318 "src/bin/pgaftest/test_spec_parse.y" { pgaf_next_brace_is_while = 1; ;} break; - case 167: -#line 1309 "test_spec_parse.y" + case 169: +#line 1319 "src/bin/pgaftest/test_spec_parse.y" { (yyval.step) = (yyvsp[(4) - (5)].step); ;} break; - case 168: -#line 1314 "test_spec_parse.y" + case 170: +#line 1324 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_STAYS_WHILE); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (5)].str), sizeof((yyval.cmd)->service)); @@ -3230,8 +3259,8 @@ yyparse () ;} break; - case 169: -#line 1333 "test_spec_parse.y" + case 171: +#line 1343 "src/bin/pgaftest/test_spec_parse.y" { /* only "set monitor " is supported; $2 must be "monitor" */ if (strcmp((yyvsp[(2) - (3)].str), "monitor") != 0) @@ -3246,8 +3275,8 @@ yyparse () ;} break; - case 170: -#line 1358 "test_spec_parse.y" + case 172: +#line 1368 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_LOGS_CHECK); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (4)].str), sizeof((yyval.cmd)->service)); @@ -3258,8 +3287,8 @@ yyparse () ;} break; - case 171: -#line 1367 "test_spec_parse.y" + case 173: +#line 1377 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_LOGS_CHECK); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (5)].str), sizeof((yyval.cmd)->service)); @@ -3270,8 +3299,8 @@ yyparse () ;} break; - case 172: -#line 1376 "test_spec_parse.y" + case 174: +#line 1386 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_LOGS_CHECK); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (4)].str), sizeof((yyval.cmd)->service)); @@ -3282,8 +3311,8 @@ yyparse () ;} break; - case 173: -#line 1385 "test_spec_parse.y" + case 175: +#line 1395 "src/bin/pgaftest/test_spec_parse.y" { (yyval.cmd) = make_cmd(CMD_LOGS_CHECK); strlcpy((yyval.cmd)->service, (yyvsp[(2) - (5)].str), sizeof((yyval.cmd)->service)); @@ -3294,8 +3323,8 @@ yyparse () ;} break; - case 176: -#line 1406 "test_spec_parse.y" + case 178: +#line 1416 "src/bin/pgaftest/test_spec_parse.y" { int i = current_spec->sequenceLength; if (i < PGAF_MAX_SEQ) @@ -3309,124 +3338,124 @@ yyparse () ;} break; - case 177: -#line 1427 "test_spec_parse.y" + case 179: +#line 1437 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "init"; ;} break; - case 178: -#line 1428 "test_spec_parse.y" + case 180: +#line 1438 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "single"; ;} break; - case 179: -#line 1429 "test_spec_parse.y" + case 181: +#line 1439 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "primary"; ;} break; - case 180: -#line 1430 "test_spec_parse.y" + case 182: +#line 1440 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "wait_primary"; ;} break; - case 181: -#line 1431 "test_spec_parse.y" + case 183: +#line 1441 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "wait_standby"; ;} break; - case 182: -#line 1432 "test_spec_parse.y" + case 184: +#line 1442 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "demoted"; ;} break; - case 183: -#line 1433 "test_spec_parse.y" + case 185: +#line 1443 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "demote_timeout"; ;} break; - case 184: -#line 1434 "test_spec_parse.y" + case 186: +#line 1444 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "draining"; ;} break; - case 185: -#line 1435 "test_spec_parse.y" + case 187: +#line 1445 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "secondary"; ;} break; - case 186: -#line 1436 "test_spec_parse.y" + case 188: +#line 1446 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "catchingup"; ;} break; - case 187: -#line 1437 "test_spec_parse.y" + case 189: +#line 1447 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "prepare_promotion"; ;} break; - case 188: -#line 1438 "test_spec_parse.y" + case 190: +#line 1448 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "stop_replication"; ;} break; - case 189: -#line 1439 "test_spec_parse.y" + case 191: +#line 1449 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "maintenance"; ;} break; - case 190: -#line 1440 "test_spec_parse.y" + case 192: +#line 1450 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "join_primary"; ;} break; - case 191: -#line 1441 "test_spec_parse.y" + case 193: +#line 1451 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "apply_settings"; ;} break; - case 192: -#line 1442 "test_spec_parse.y" + case 194: +#line 1452 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "prepare_maintenance"; ;} break; - case 193: -#line 1443 "test_spec_parse.y" + case 195: +#line 1453 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "wait_maintenance"; ;} break; - case 194: -#line 1444 "test_spec_parse.y" + case 196: +#line 1454 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "report_lsn"; ;} break; - case 195: -#line 1445 "test_spec_parse.y" + case 197: +#line 1455 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "fast_forward"; ;} break; - case 196: -#line 1446 "test_spec_parse.y" + case 198: +#line 1456 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "join_secondary"; ;} break; - case 197: -#line 1447 "test_spec_parse.y" + case 199: +#line 1457 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = "dropped"; ;} break; - case 198: -#line 1455 "test_spec_parse.y" + case 200: +#line 1465 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; - case 199: -#line 1456 "test_spec_parse.y" + case 201: +#line 1466 "src/bin/pgaftest/test_spec_parse.y" { (yyval.str) = (yyvsp[(1) - (1)].str); ;} break; /* Line 1267 of yacc.c. */ -#line 3430 "test_spec_parse.c" +#line 3459 "src/bin/pgaftest/test_spec_parse.c" default: break; } YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); @@ -3640,7 +3669,7 @@ yyparse () } -#line 1459 "test_spec_parse.y" +#line 1469 "src/bin/pgaftest/test_spec_parse.y" /* ----------------------------------------------------------------------- diff --git a/src/bin/pgaftest/test_spec_parse.h b/src/bin/pgaftest/test_spec_parse.h index d32a05a5d..0e650a964 100644 --- a/src/bin/pgaftest/test_spec_parse.h +++ b/src/bin/pgaftest/test_spec_parse.h @@ -80,74 +80,75 @@ T_REPLICATION_PASSWORD = 296, T_EXTENSION_VERSION = 297, T_BIND_SOURCE = 298, - T_FS_INIT = 299, - T_FS_SINGLE = 300, - T_FS_PRIMARY = 301, - T_FS_WAIT_PRIMARY = 302, - T_FS_WAIT_STANDBY = 303, - T_FS_DEMOTED = 304, - T_FS_DEMOTE_TIMEOUT = 305, - T_FS_DRAINING = 306, - T_FS_SECONDARY = 307, - T_FS_CATCHINGUP = 308, - T_FS_PREP_PROMOTION = 309, - T_FS_STOP_REPLICATION = 310, - T_FS_MAINTENANCE = 311, - T_FS_JOIN_PRIMARY = 312, - T_FS_APPLY_SETTINGS = 313, - T_FS_PREPARE_MAINTENANCE = 314, - T_FS_WAIT_MAINTENANCE = 315, - T_FS_REPORT_LSN = 316, - T_FS_FAST_FORWARD = 317, - T_FS_JOIN_SECONDARY = 318, - T_FS_DROPPED = 319, - T_EXEC = 320, - T_EXEC_FAILS = 321, - T_RUN = 322, - T_PG_AUTOCTL = 323, - T_WAIT = 324, - T_UNTIL = 325, - T_TIMEOUT = 326, - T_AND = 327, - T_IS = 328, - T_WITH = 329, - T_ASSERT = 330, - T_SQL = 331, - T_EXPECT = 332, - T_ERROR = 333, - T_PROMOTE = 334, - T_NETWORK = 335, - T_DISCONNECT = 336, - T_CONNECT = 337, - T_SLEEP = 338, - T_COMPOSE = 339, - T_DOWN = 340, - T_START = 341, - T_STOP = 342, - T_STOPPED = 343, - T_KILL = 344, - T_INJECT = 345, - T_STATE = 346, - T_ASSIGNED_STATE = 347, - T_IN = 348, - T_GROUP = 349, - T_LBRACE = 350, - T_RBRACE = 351, - T_COMMA = 352, - T_POSTGRES = 353, - T_STAYS = 354, - T_WHILE = 355, - T_THROUGH = 356, - T_SET = 357, - T_LOGS = 358, - T_NOT = 359, - T_CONTAINS = 360, - T_MATCHES = 361, - T_INTEGER = 362, - T_IDENT = 363, - T_STRING = 364, - T_BLOCK = 365, - T_SHELL_ARGS = 366 + T_REGION = 299, + T_FS_INIT = 300, + T_FS_SINGLE = 301, + T_FS_PRIMARY = 302, + T_FS_WAIT_PRIMARY = 303, + T_FS_WAIT_STANDBY = 304, + T_FS_DEMOTED = 305, + T_FS_DEMOTE_TIMEOUT = 306, + T_FS_DRAINING = 307, + T_FS_SECONDARY = 308, + T_FS_CATCHINGUP = 309, + T_FS_PREP_PROMOTION = 310, + T_FS_STOP_REPLICATION = 311, + T_FS_MAINTENANCE = 312, + T_FS_JOIN_PRIMARY = 313, + T_FS_APPLY_SETTINGS = 314, + T_FS_PREPARE_MAINTENANCE = 315, + T_FS_WAIT_MAINTENANCE = 316, + T_FS_REPORT_LSN = 317, + T_FS_FAST_FORWARD = 318, + T_FS_JOIN_SECONDARY = 319, + T_FS_DROPPED = 320, + T_EXEC = 321, + T_EXEC_FAILS = 322, + T_RUN = 323, + T_PG_AUTOCTL = 324, + T_WAIT = 325, + T_UNTIL = 326, + T_TIMEOUT = 327, + T_AND = 328, + T_IS = 329, + T_WITH = 330, + T_ASSERT = 331, + T_SQL = 332, + T_EXPECT = 333, + T_ERROR = 334, + T_PROMOTE = 335, + T_NETWORK = 336, + T_DISCONNECT = 337, + T_CONNECT = 338, + T_SLEEP = 339, + T_COMPOSE = 340, + T_DOWN = 341, + T_START = 342, + T_STOP = 343, + T_STOPPED = 344, + T_KILL = 345, + T_INJECT = 346, + T_STATE = 347, + T_ASSIGNED_STATE = 348, + T_IN = 349, + T_GROUP = 350, + T_LBRACE = 351, + T_RBRACE = 352, + T_COMMA = 353, + T_POSTGRES = 354, + T_STAYS = 355, + T_WHILE = 356, + T_THROUGH = 357, + T_SET = 358, + T_LOGS = 359, + T_NOT = 360, + T_CONTAINS = 361, + T_MATCHES = 362, + T_INTEGER = 363, + T_IDENT = 364, + T_STRING = 365, + T_BLOCK = 366, + T_SHELL_ARGS = 367 }; #endif /* Tokens. */ @@ -192,81 +193,82 @@ #define T_REPLICATION_PASSWORD 296 #define T_EXTENSION_VERSION 297 #define T_BIND_SOURCE 298 -#define T_FS_INIT 299 -#define T_FS_SINGLE 300 -#define T_FS_PRIMARY 301 -#define T_FS_WAIT_PRIMARY 302 -#define T_FS_WAIT_STANDBY 303 -#define T_FS_DEMOTED 304 -#define T_FS_DEMOTE_TIMEOUT 305 -#define T_FS_DRAINING 306 -#define T_FS_SECONDARY 307 -#define T_FS_CATCHINGUP 308 -#define T_FS_PREP_PROMOTION 309 -#define T_FS_STOP_REPLICATION 310 -#define T_FS_MAINTENANCE 311 -#define T_FS_JOIN_PRIMARY 312 -#define T_FS_APPLY_SETTINGS 313 -#define T_FS_PREPARE_MAINTENANCE 314 -#define T_FS_WAIT_MAINTENANCE 315 -#define T_FS_REPORT_LSN 316 -#define T_FS_FAST_FORWARD 317 -#define T_FS_JOIN_SECONDARY 318 -#define T_FS_DROPPED 319 -#define T_EXEC 320 -#define T_EXEC_FAILS 321 -#define T_RUN 322 -#define T_PG_AUTOCTL 323 -#define T_WAIT 324 -#define T_UNTIL 325 -#define T_TIMEOUT 326 -#define T_AND 327 -#define T_IS 328 -#define T_WITH 329 -#define T_ASSERT 330 -#define T_SQL 331 -#define T_EXPECT 332 -#define T_ERROR 333 -#define T_PROMOTE 334 -#define T_NETWORK 335 -#define T_DISCONNECT 336 -#define T_CONNECT 337 -#define T_SLEEP 338 -#define T_COMPOSE 339 -#define T_DOWN 340 -#define T_START 341 -#define T_STOP 342 -#define T_STOPPED 343 -#define T_KILL 344 -#define T_INJECT 345 -#define T_STATE 346 -#define T_ASSIGNED_STATE 347 -#define T_IN 348 -#define T_GROUP 349 -#define T_LBRACE 350 -#define T_RBRACE 351 -#define T_COMMA 352 -#define T_POSTGRES 353 -#define T_STAYS 354 -#define T_WHILE 355 -#define T_THROUGH 356 -#define T_SET 357 -#define T_LOGS 358 -#define T_NOT 359 -#define T_CONTAINS 360 -#define T_MATCHES 361 -#define T_INTEGER 362 -#define T_IDENT 363 -#define T_STRING 364 -#define T_BLOCK 365 -#define T_SHELL_ARGS 366 +#define T_REGION 299 +#define T_FS_INIT 300 +#define T_FS_SINGLE 301 +#define T_FS_PRIMARY 302 +#define T_FS_WAIT_PRIMARY 303 +#define T_FS_WAIT_STANDBY 304 +#define T_FS_DEMOTED 305 +#define T_FS_DEMOTE_TIMEOUT 306 +#define T_FS_DRAINING 307 +#define T_FS_SECONDARY 308 +#define T_FS_CATCHINGUP 309 +#define T_FS_PREP_PROMOTION 310 +#define T_FS_STOP_REPLICATION 311 +#define T_FS_MAINTENANCE 312 +#define T_FS_JOIN_PRIMARY 313 +#define T_FS_APPLY_SETTINGS 314 +#define T_FS_PREPARE_MAINTENANCE 315 +#define T_FS_WAIT_MAINTENANCE 316 +#define T_FS_REPORT_LSN 317 +#define T_FS_FAST_FORWARD 318 +#define T_FS_JOIN_SECONDARY 319 +#define T_FS_DROPPED 320 +#define T_EXEC 321 +#define T_EXEC_FAILS 322 +#define T_RUN 323 +#define T_PG_AUTOCTL 324 +#define T_WAIT 325 +#define T_UNTIL 326 +#define T_TIMEOUT 327 +#define T_AND 328 +#define T_IS 329 +#define T_WITH 330 +#define T_ASSERT 331 +#define T_SQL 332 +#define T_EXPECT 333 +#define T_ERROR 334 +#define T_PROMOTE 335 +#define T_NETWORK 336 +#define T_DISCONNECT 337 +#define T_CONNECT 338 +#define T_SLEEP 339 +#define T_COMPOSE 340 +#define T_DOWN 341 +#define T_START 342 +#define T_STOP 343 +#define T_STOPPED 344 +#define T_KILL 345 +#define T_INJECT 346 +#define T_STATE 347 +#define T_ASSIGNED_STATE 348 +#define T_IN 349 +#define T_GROUP 350 +#define T_LBRACE 351 +#define T_RBRACE 352 +#define T_COMMA 353 +#define T_POSTGRES 354 +#define T_STAYS 355 +#define T_WHILE 356 +#define T_THROUGH 357 +#define T_SET 358 +#define T_LOGS 359 +#define T_NOT 360 +#define T_CONTAINS 361 +#define T_MATCHES 362 +#define T_INTEGER 363 +#define T_IDENT 364 +#define T_STRING 365 +#define T_BLOCK 366 +#define T_SHELL_ARGS 367 #if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED typedef union YYSTYPE -#line 145 "test_spec_parse.y" +#line 145 "src/bin/pgaftest/test_spec_parse.y" { int ival; char *str; @@ -274,7 +276,7 @@ typedef union YYSTYPE TestCmd *cmd; } /* Line 1529 of yacc.c. */ -#line 278 "test_spec_parse.h" +#line 280 "src/bin/pgaftest/test_spec_parse.h" YYSTYPE; # define yystype YYSTYPE /* obsolescent; will be withdrawn */ # define YYSTYPE_IS_DECLARED 1 diff --git a/src/bin/pgaftest/test_spec_parse.y b/src/bin/pgaftest/test_spec_parse.y index f639f6242..cf52c8286 100644 --- a/src/bin/pgaftest/test_spec_parse.y +++ b/src/bin/pgaftest/test_spec_parse.y @@ -160,7 +160,7 @@ static TestNode *current_node = NULL; %token T_LAUNCH T_CREATE T_DEFERRED T_IMMEDIATE T_FALSE T_TRUE T_INITIALLY T_VOLUME %token T_LISTEN T_CITUS_SECONDARY T_CANDIDATE_PRIORITY T_PORT T_PASSWORD T_MONITOR_PASSWORD %token T_CITUS_CLUSTER_NAME T_DEBIAN_CLUSTER T_REPLICATION_QUORUM T_REPLICATION_PASSWORD -%token T_EXTENSION_VERSION T_BIND_SOURCE +%token T_EXTENSION_VERSION T_BIND_SOURCE T_REGION /* ---- FSM state tokens (used in CLUSTER_BODY and STEP_BODY) ---- */ %token T_FS_INIT T_FS_SINGLE T_FS_PRIMARY @@ -557,6 +557,16 @@ node_opt: { current_node->candidatePriority = $2; } + | T_REGION T_IDENT + { + strlcpy(current_node->region, $2, sizeof(current_node->region)); + free($2); + } + | T_REGION T_STRING + { + strlcpy(current_node->region, $2, sizeof(current_node->region)); + free($2); + } | T_GROUP T_INTEGER { current_node->group = $2; diff --git a/src/bin/pgaftest/test_spec_scan.c b/src/bin/pgaftest/test_spec_scan.c index 654aac062..d985a92dd 100644 --- a/src/bin/pgaftest/test_spec_scan.c +++ b/src/bin/pgaftest/test_spec_scan.c @@ -1,6 +1,6 @@ -#line 1 "test_spec_scan.c" +#line 1 "src/bin/pgaftest/test_spec_scan.c" -#line 3 "test_spec_scan.c" +#line 3 "src/bin/pgaftest/test_spec_scan.c" #define YY_INT_ALIGNED short int @@ -356,8 +356,8 @@ static void yynoreturn yy_fatal_error ( const char* msg ); (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; -#define YY_NUM_RULES 152 -#define YY_END_OF_BUFFER 153 +#define YY_NUM_RULES 153 +#define YY_END_OF_BUFFER 154 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -365,137 +365,138 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static const flex_int16_t yy_accept[1178] = +static const flex_int16_t yy_accept[1182] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 153, 18, 17, 16, 18, 1, 12, 11, 13, 13, - 13, 13, 13, 13, 15, 152, 21, 20, 152, 19, - 59, 58, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 61, 62, 99, 98, 152, 97, 131, 142, 130, - 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 146, 144, - 145, 148, 147, 149, 150, 151, 17, 0, 14, 1, + 154, 18, 17, 16, 18, 1, 12, 11, 13, 13, + 13, 13, 13, 13, 15, 153, 21, 20, 153, 19, + 60, 59, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 62, 63, 100, 99, 153, 98, 132, 143, 131, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 145, + 146, 149, 148, 150, 151, 152, 17, 0, 14, 1, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, - 21, 0, 60, 19, 59, 59, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 99, 0, 143, 97, 142, 142, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 122, 128, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 148, 147, 150, - 13, 13, 13, 13, 13, 13, 13, 13, 43, 96, - - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 25, 96, 96, 96, - 96, 96, 127, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 139, 146, 146, - 146, 146, 146, 146, 102, 146, 136, 146, 146, 108, - 146, 146, 146, 146, 146, 146, 146, 146, 13, 13, - 13, 4, 13, 13, 9, 13, 96, 96, 27, 96, - - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 63, 96, 96, - 96, 96, 96, 96, 30, 96, 96, 51, 96, 96, - 96, 96, 96, 96, 96, 42, 96, 96, 96, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 146, 117, - 146, 146, 146, 101, 146, 146, 146, 63, 146, 146, - 121, 138, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 119, 146, 146, - 146, 104, 146, 129, 13, 13, 13, 13, 7, 13, - 96, 33, 96, 96, 96, 96, 96, 96, 96, 96, - - 96, 96, 96, 96, 96, 41, 96, 96, 96, 50, - 24, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 110, 146, 146, - 146, 146, 126, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 115, 118, 123, - 133, 146, 146, 146, 146, 146, 105, 146, 146, 134, - 13, 13, 13, 13, 13, 96, 96, 96, 96, 96, - 96, 96, 96, 38, 96, 96, 96, 96, 96, 96, - - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 37, 47, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 64, 96, 96, 96, 46, 96, 96, 96, - 96, 96, 96, 32, 146, 146, 107, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 109, 146, - 146, 137, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 64, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 13, 13, - 2, 3, 13, 13, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 70, 96, 95, - - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 22, 96, 96, 96, 96, 65, 96, 96, - 96, 96, 96, 96, 45, 96, 96, 96, 96, 96, - 96, 146, 146, 146, 146, 146, 116, 114, 146, 146, - 146, 70, 146, 146, 95, 146, 146, 146, 146, 146, - 146, 146, 146, 141, 112, 146, 146, 146, 65, 111, - 146, 146, 146, 146, 146, 120, 135, 106, 146, 146, - 146, 146, 146, 146, 13, 13, 10, 8, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 39, 96, - 96, 73, 96, 96, 96, 96, 96, 96, 96, 96, - - 96, 96, 96, 96, 96, 96, 29, 35, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 146, 146, 146, 146, 146, 140, 146, 146, - 146, 73, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 132, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 13, 13, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 28, 96, 40, 44, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 74, 96, 96, 96, 96, 96, 96, 96, 96, 146, - - 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 74, 146, 146, 146, 146, 146, 146, 146, - 146, 13, 13, 96, 96, 96, 96, 96, 75, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 34, 96, 96, 96, 96, - 96, 90, 89, 96, 96, 96, 96, 96, 96, 96, - 96, 146, 146, 146, 146, 75, 146, 146, 113, 100, - 146, 146, 146, 146, 146, 146, 146, 103, 146, 146, - 146, 146, 90, 89, 146, 146, 146, 146, 146, 146, - - 146, 146, 13, 13, 96, 96, 26, 57, 96, 96, - 96, 31, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 80, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 80, 146, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 13, 6, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 92, 91, 23, 82, 96, 81, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 67, 69, 96, 66, 68, 146, 146, 146, 146, 146, - - 146, 92, 91, 82, 146, 81, 146, 146, 146, 146, - 146, 146, 146, 146, 67, 69, 146, 66, 68, 13, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 146, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 146, 146, 146, 146, 146, 146, 13, 84, - 83, 96, 96, 96, 53, 72, 71, 96, 94, 93, - 96, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 84, 83, 124, 146, 72, 71, 94, 93, 146, - 146, 146, 146, 146, 146, 146, 146, 13, 96, 96, - - 48, 96, 96, 96, 96, 96, 96, 96, 96, 96, - 96, 96, 96, 146, 146, 146, 146, 146, 146, 146, - 146, 146, 13, 96, 96, 96, 36, 96, 96, 96, - 96, 96, 96, 79, 78, 88, 87, 146, 146, 146, - 146, 146, 79, 78, 88, 87, 5, 96, 96, 56, - 96, 77, 96, 76, 96, 96, 146, 146, 77, 146, - 76, 49, 52, 96, 96, 96, 54, 125, 146, 146, - 86, 85, 96, 86, 85, 55, 0 + 21, 0, 61, 19, 60, 60, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 100, 0, 144, 98, 143, 143, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 123, 129, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 149, 148, 151, + 13, 13, 13, 13, 13, 13, 13, 13, 43, 97, + + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 25, 97, 97, + 97, 97, 97, 128, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 140, 147, + 147, 147, 147, 147, 147, 103, 147, 137, 147, 147, + 109, 147, 147, 147, 147, 147, 147, 147, 147, 13, + 13, 13, 4, 13, 13, 9, 13, 97, 97, 27, + + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 64, 97, + 97, 97, 97, 97, 97, 30, 97, 97, 52, 97, + 97, 97, 97, 97, 97, 97, 97, 42, 97, 97, + 97, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 118, 147, 147, 147, 102, 147, 147, 147, 64, + 147, 147, 122, 139, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 120, + 147, 147, 147, 105, 147, 130, 13, 13, 13, 13, + 7, 13, 97, 33, 97, 97, 97, 97, 97, 97, + + 97, 97, 97, 97, 97, 97, 97, 41, 97, 97, + 97, 51, 24, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 111, 147, 147, 147, 147, 127, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 116, 119, 124, 134, 147, 147, 147, 147, 147, 106, + 147, 147, 135, 13, 13, 13, 13, 13, 97, 97, + 97, 97, 97, 97, 97, 97, 38, 97, 97, 97, + + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 37, 47, 97, 97, 97, 97, 97, + 97, 97, 50, 97, 97, 97, 65, 97, 97, 97, + 46, 97, 97, 97, 97, 97, 97, 32, 147, 147, + 108, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 110, 147, 147, 138, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 65, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 13, 13, 2, 3, 13, 13, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + + 97, 71, 97, 96, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 22, 97, 97, 97, + 97, 66, 97, 97, 97, 97, 97, 97, 45, 97, + 97, 97, 97, 97, 97, 147, 147, 147, 147, 147, + 117, 115, 147, 147, 147, 71, 147, 147, 96, 147, + 147, 147, 147, 147, 147, 147, 147, 142, 113, 147, + 147, 147, 66, 112, 147, 147, 147, 147, 147, 121, + 136, 107, 147, 147, 147, 147, 147, 147, 13, 13, + 10, 8, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 39, 97, 97, 74, 97, 97, 97, 97, + + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 29, 35, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 147, 147, 147, 147, + 147, 141, 147, 147, 147, 74, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 133, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 13, + 13, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 28, 97, 40, 44, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 75, 97, 97, 97, 97, 97, + + 97, 97, 97, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 75, 147, 147, 147, + 147, 147, 147, 147, 147, 13, 13, 97, 97, 97, + 97, 97, 76, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 34, + 97, 97, 97, 97, 97, 91, 90, 97, 97, 97, + 97, 97, 97, 97, 97, 147, 147, 147, 147, 76, + 147, 147, 114, 101, 147, 147, 147, 147, 147, 147, + 147, 104, 147, 147, 147, 147, 91, 90, 147, 147, + + 147, 147, 147, 147, 147, 147, 13, 13, 97, 97, + 26, 58, 97, 97, 97, 31, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 81, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 81, 147, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 13, 6, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 93, 92, + 23, 83, 97, 82, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 68, 70, 97, 67, 69, 147, + + 147, 147, 147, 147, 147, 93, 92, 83, 147, 82, + 147, 147, 147, 147, 147, 147, 147, 147, 68, 70, + 147, 67, 69, 13, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 147, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 147, 147, 147, 147, + 147, 147, 13, 85, 84, 97, 97, 97, 54, 73, + 72, 97, 95, 94, 97, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 85, 84, 125, 147, 73, + 72, 95, 94, 147, 147, 147, 147, 147, 147, 147, + + 147, 13, 97, 97, 48, 97, 97, 97, 97, 97, + 97, 97, 97, 97, 97, 97, 97, 147, 147, 147, + 147, 147, 147, 147, 147, 147, 13, 97, 97, 97, + 36, 97, 97, 97, 97, 97, 97, 80, 79, 89, + 88, 147, 147, 147, 147, 147, 80, 79, 89, 88, + 5, 97, 97, 57, 97, 78, 97, 77, 97, 97, + 147, 147, 78, 147, 77, 49, 53, 97, 97, 97, + 55, 126, 147, 147, 87, 86, 97, 87, 86, 56, + 0 } ; static const YY_CHAR yy_ec[256] = @@ -538,275 +539,279 @@ static const YY_CHAR yy_meta[41] = 4, 4, 4, 4, 4, 4, 4, 4, 1, 1 } ; -static const flex_int16_t yy_base[1191] = +static const flex_int16_t yy_base[1195] = { 0, - 0, 0, 40, 0, 80, 0, 119, 121, 1265, 1264, - 1266, 1269, 123, 1269, 1260, 0, 117, 1269, 0, 106, - 1236, 1235, 112, 1244, 1269, 1269, 130, 1269, 1256, 0, - 124, 1269, 0, 108, 1238, 124, 123, 1222, 125, 1227, - 117, 1229, 136, 133, 123, 134, 1238, 141, 1224, 1226, - 150, 1269, 1269, 164, 1269, 1248, 0, 1269, 158, 1269, - 0, 148, 155, 154, 150, 1238, 1220, 152, 1222, 1227, - 1220, 1233, 168, 169, 170, 173, 171, 1219, 180, 1269, - 1269, 0, 1243, 1269, 0, 1269, 203, 1239, 1269, 0, - 199, 1269, 0, 1210, 1208, 1214, 1223, 179, 1221, 1224, - - 211, 1232, 1269, 0, 205, 1269, 0, 1219, 1206, 1196, - 1200, 1205, 183, 1198, 1202, 1211, 203, 205, 1195, 195, - 1196, 1198, 209, 1203, 1202, 1189, 1190, 1199, 1193, 213, - 1193, 1186, 1186, 206, 1187, 1199, 1187, 1188, 1184, 1177, - 1185, 1187, 1177, 230, 1202, 1269, 0, 227, 1269, 0, - 1189, 1176, 1172, 211, 199, 1177, 1170, 1165, 226, 1169, - 142, 1167, 1170, 219, 0, 1175, 1171, 1175, 223, 1161, - 1160, 1179, 1159, 225, 1161, 1162, 230, 1161, 1169, 1161, - 234, 1154, 1158, 1150, 1160, 1159, 1147, 0, 1177, 0, - 1144, 1145, 1154, 1157, 1140, 1139, 1143, 1140, 0, 1145, - - 1142, 1147, 1150, 1149, 1149, 1130, 1132, 1148, 1139, 1142, - 1131, 1136, 1128, 1138, 1123, 1121, 1127, 1118, 1131, 1132, - 1116, 1121, 1120, 1113, 1118, 1122, 1117, 1124, 1133, 1108, - 1106, 1109, 1111, 224, 1108, 1115, 0, 1105, 1115, 1098, - 1098, 1106, 0, 1104, 233, 1111, 1111, 1097, 231, 1097, - 1108, 1096, 1100, 1092, 1092, 1103, 1100, 1084, 1082, 1082, - 1096, 1086, 1087, 1079, 1083, 1093, 1072, 0, 1093, 1073, - 1076, 1078, 1077, 1074, 0, 1073, 0, 1080, 1081, 0, - 234, 1069, 1069, 1078, 1073, 1061, 1068, 1071, 1059, 1057, - 1056, 0, 1070, 1058, 0, 1069, 1047, 1068, 1075, 1074, - - 1059, 1059, 1047, 1061, 1044, 1062, 1044, 1041, 1046, 1043, - 1044, 1052, 253, 1055, 1039, 1049, 1049, 1043, 260, 1048, - 1045, 1029, 1028, 1032, 0, 1027, 1022, 0, 1043, 1042, - 1033, 1023, 1026, 1027, 261, 0, 1025, 262, 1032, 1011, - 1017, 1027, 1024, 1024, 1016, 1025, 1028, 1008, 1012, 0, - 1012, 1009, 1006, 1028, 1019, 263, 1005, 0, 1017, 269, - 0, 0, 999, 1010, 1002, 995, 1008, 1013, 1012, 997, - 993, 996, 997, 992, 987, 1001, 986, 270, 983, 988, - 990, 271, 996, 0, 1005, 994, 983, 983, 0, 981, - 272, 0, 982, 975, 989, 983, 996, 981, 984, 974, - - 969, 981, 976, 979, 964, 0, 976, 975, 960, 0, - 984, 969, 976, 228, 257, 968, 961, 969, 958, 958, - 946, 955, 951, 950, 964, 946, 961, 959, 945, 944, - 956, 955, 262, 266, 941, 288, 938, 943, 952, 946, - 935, 950, 943, 946, 936, 940, 943, 0, 941, 926, - 939, 938, 0, 923, 268, 273, 937, 936, 922, 919, - 920, 919, 918, 915, 914, 929, 927, 0, 0, 0, - 0, 913, 912, 924, 921, 906, 0, 277, 278, 0, - 277, 908, 907, 921, 900, 903, 902, 915, 904, 917, - 903, 292, 902, 0, 920, 909, 303, 899, 908, 902, - - 895, 894, 899, 887, 905, 893, 886, 898, 884, 896, - 0, 0, 886, 881, 889, 883, 878, 890, 869, 892, - 304, 891, 0, 886, 885, 885, 0, 887, 869, 866, - 884, 866, 863, 0, 863, 862, 0, 875, 878, 864, - 872, 856, 861, 306, 860, 859, 868, 870, 0, 855, - 854, 0, 850, 862, 848, 860, 850, 844, 851, 846, - 855, 854, 833, 852, 313, 855, 0, 850, 849, 849, - 844, 831, 849, 831, 828, 846, 828, 825, 829, 828, - 0, 0, 837, 827, 835, 834, 818, 816, 816, 828, - 822, 828, 831, 828, 826, 809, 808, 0, 820, 0, - - 811, 807, 806, 808, 821, 801, 808, 810, 815, 808, - 813, 814, 819, 793, 809, 807, 314, 0, 790, 797, - 796, 789, 790, 789, 0, 795, 794, 801, 792, 791, - 798, 793, 792, 792, 775, 787, 0, 0, 774, 772, - 771, 0, 785, 782, 0, 779, 769, 768, 776, 781, - 774, 779, 780, 0, 0, 777, 760, 317, 0, 0, - 766, 765, 758, 759, 758, 0, 0, 0, 764, 763, - 770, 761, 760, 767, 752, 748, 0, 0, 745, 744, - 755, 744, 756, 739, 737, 751, 733, 174, 0, 228, - 259, 0, 260, 279, 282, 301, 298, 313, 294, 307, - - 306, 309, 308, 310, 309, 311, 0, 0, 314, 315, - 320, 313, 314, 309, 323, 324, 323, 325, 325, 326, - 328, 328, 323, 324, 350, 341, 326, 0, 339, 340, - 347, 0, 339, 329, 330, 341, 340, 343, 342, 344, - 339, 0, 347, 348, 343, 346, 341, 355, 356, 355, - 357, 357, 358, 360, 360, 357, 365, 357, 358, 364, - 377, 386, 366, 364, 369, 370, 365, 374, 375, 394, - 389, 390, 0, 385, 0, 0, 392, 380, 394, 382, - 394, 397, 381, 399, 383, 401, 385, 389, 391, 392, - 0, 398, 399, 389, 409, 407, 392, 412, 410, 395, - - 396, 398, 423, 403, 407, 408, 402, 404, 423, 424, - 425, 413, 427, 415, 427, 419, 431, 415, 433, 417, - 422, 423, 0, 429, 430, 420, 440, 438, 423, 443, - 441, 442, 442, 439, 440, 446, 446, 436, 0, 433, - 440, 437, 437, 452, 453, 437, 442, 443, 457, 445, - 460, 447, 462, 462, 449, 0, 460, 455, 462, 457, - 459, 0, 0, 471, 472, 471, 459, 476, 474, 462, - 479, 473, 474, 464, 469, 0, 481, 482, 0, 0, - 470, 471, 472, 487, 474, 489, 489, 0, 486, 481, - 488, 483, 0, 0, 496, 497, 496, 484, 501, 499, - - 487, 504, 498, 490, 495, 496, 0, 0, 493, 507, - 509, 0, 494, 500, 501, 512, 514, 515, 500, 496, - 521, 498, 523, 0, 506, 512, 514, 514, 516, 535, - 530, 531, 519, 509, 510, 522, 512, 513, 525, 526, - 540, 524, 528, 529, 541, 542, 522, 547, 524, 549, - 0, 537, 539, 539, 541, 554, 555, 543, 533, 534, - 546, 536, 537, 549, 0, 557, 558, 557, 549, 567, - 564, 549, 550, 554, 0, 0, 0, 0, 555, 0, - 556, 552, 556, 562, 558, 564, 564, 562, 563, 583, - 0, 0, 584, 0, 0, 579, 580, 568, 580, 569, - - 570, 0, 0, 0, 574, 0, 575, 574, 580, 576, - 582, 578, 579, 599, 0, 0, 600, 0, 0, 601, - 584, 585, 590, 611, 589, 590, 589, 590, 592, 587, - 588, 599, 610, 596, 612, 598, 618, 599, 612, 613, - 609, 610, 606, 607, 622, 613, 609, 610, 606, 607, - 628, 614, 630, 616, 628, 629, 625, 626, 621, 0, - 0, 624, 629, 619, 0, 0, 0, 636, 0, 0, - 628, 633, 639, 635, 641, 632, 637, 638, 639, 652, - 653, 0, 0, 0, 639, 0, 0, 0, 0, 644, - 650, 646, 652, 647, 648, 661, 662, 651, 658, 667, - - 0, 654, 666, 670, 657, 672, 659, 656, 658, 663, - 664, 674, 675, 672, 681, 668, 683, 670, 672, 673, - 683, 684, 672, 671, 679, 679, 0, 680, 681, 682, - 683, 675, 678, 0, 0, 0, 0, 680, 687, 688, - 689, 690, 0, 0, 0, 0, 0, 680, 701, 0, - 704, 0, 705, 0, 694, 697, 686, 709, 0, 710, - 0, 0, 0, 709, 710, 698, 0, 0, 712, 713, - 0, 0, 715, 0, 0, 0, 1269, 732, 736, 740, - 744, 743, 748, 752, 751, 756, 760, 759, 764, 768 + 0, 0, 40, 0, 80, 0, 119, 121, 1269, 1268, + 1270, 1273, 123, 1273, 1264, 0, 117, 1273, 0, 106, + 1240, 1239, 112, 1248, 1273, 1273, 130, 1273, 1260, 0, + 124, 1273, 0, 108, 1242, 124, 123, 1226, 125, 1231, + 117, 1233, 136, 133, 123, 134, 1242, 141, 1228, 1230, + 150, 1273, 1273, 164, 1273, 1252, 0, 1273, 158, 1273, + 0, 148, 155, 154, 150, 1242, 1224, 152, 1226, 1231, + 1224, 1237, 168, 169, 170, 173, 171, 1223, 180, 1273, + 1273, 0, 1247, 1273, 0, 1273, 203, 1243, 1273, 0, + 199, 1273, 0, 1214, 1212, 1218, 1227, 179, 1225, 1228, + + 211, 1236, 1273, 0, 205, 1273, 0, 1223, 1210, 1200, + 1204, 1209, 183, 1202, 1206, 1215, 203, 205, 1199, 195, + 1200, 1202, 209, 1207, 1206, 1193, 1194, 1203, 1197, 213, + 1197, 1190, 1190, 206, 205, 1204, 1192, 1193, 1189, 1182, + 1190, 1192, 1182, 234, 1207, 1273, 0, 230, 1273, 0, + 1194, 1181, 1177, 199, 214, 1182, 1175, 1170, 229, 1174, + 142, 1172, 1175, 222, 0, 1180, 1176, 1180, 225, 1166, + 1165, 1184, 1164, 228, 1166, 1167, 232, 1166, 1174, 1166, + 235, 1159, 1163, 1155, 1165, 1164, 1152, 0, 1182, 0, + 1149, 1150, 1159, 1162, 1145, 1144, 1148, 1145, 0, 1150, + + 1147, 1152, 1155, 1154, 1154, 1135, 1137, 1153, 1144, 1147, + 1136, 1141, 1133, 1143, 1128, 1126, 1132, 1123, 1136, 1137, + 1121, 1126, 1125, 1118, 1123, 1127, 1122, 1129, 1138, 1113, + 1111, 1114, 1116, 1119, 226, 1112, 1119, 0, 1109, 1119, + 1102, 1102, 1110, 0, 1108, 237, 1115, 1115, 1101, 233, + 1101, 1112, 1100, 1104, 1096, 1096, 1107, 1104, 1088, 1086, + 1086, 1100, 1090, 1091, 1083, 1087, 1097, 1076, 0, 1097, + 1077, 1080, 1082, 1081, 1078, 0, 1077, 0, 1084, 1085, + 0, 236, 1073, 1073, 1082, 1077, 1065, 1072, 1075, 1063, + 1061, 1060, 0, 1074, 1062, 0, 1073, 1051, 1072, 1079, + + 1078, 1063, 1063, 1051, 1065, 1048, 1066, 1048, 1045, 1050, + 1047, 1048, 1056, 260, 1059, 1043, 1053, 1053, 1047, 262, + 1052, 1049, 1033, 1032, 1036, 0, 1031, 1026, 0, 1047, + 1046, 1031, 1036, 1026, 1029, 1030, 263, 0, 1028, 264, + 1035, 1014, 1020, 1030, 1027, 1027, 1019, 1028, 1031, 1011, + 1015, 0, 1015, 1012, 1009, 1031, 1022, 270, 1008, 0, + 1020, 271, 0, 0, 1002, 1013, 1005, 998, 1011, 1016, + 1015, 1000, 996, 999, 1000, 995, 990, 1004, 989, 272, + 986, 991, 993, 273, 999, 0, 1008, 997, 986, 986, + 0, 984, 274, 0, 985, 978, 992, 986, 999, 984, + + 987, 977, 972, 984, 979, 982, 967, 0, 979, 978, + 963, 0, 987, 972, 979, 232, 259, 971, 964, 972, + 961, 961, 949, 958, 954, 953, 956, 966, 948, 963, + 961, 947, 946, 958, 957, 264, 268, 943, 290, 940, + 945, 954, 948, 937, 952, 945, 948, 938, 942, 945, + 0, 943, 928, 941, 940, 0, 925, 270, 275, 939, + 938, 924, 921, 922, 921, 920, 917, 916, 931, 929, + 0, 0, 0, 0, 915, 914, 926, 923, 908, 0, + 279, 280, 0, 279, 910, 909, 923, 902, 905, 904, + 917, 906, 919, 905, 294, 904, 0, 922, 911, 305, + + 901, 910, 904, 897, 896, 901, 889, 907, 895, 888, + 900, 886, 898, 0, 0, 888, 883, 891, 885, 880, + 892, 871, 0, 894, 306, 893, 0, 888, 887, 887, + 0, 889, 871, 868, 886, 868, 865, 0, 865, 864, + 0, 877, 880, 866, 874, 858, 863, 308, 862, 861, + 870, 872, 0, 857, 856, 0, 852, 864, 850, 862, + 852, 846, 853, 848, 857, 856, 835, 854, 315, 857, + 0, 852, 851, 851, 846, 833, 851, 833, 830, 848, + 830, 827, 831, 830, 0, 0, 839, 829, 837, 836, + 820, 818, 818, 830, 824, 830, 833, 830, 828, 811, + + 810, 0, 822, 0, 813, 809, 808, 810, 823, 803, + 810, 812, 817, 810, 815, 816, 821, 795, 811, 809, + 316, 0, 792, 799, 798, 791, 792, 791, 0, 797, + 796, 803, 794, 793, 800, 795, 794, 794, 777, 789, + 0, 0, 776, 774, 773, 0, 787, 784, 0, 781, + 771, 770, 778, 783, 776, 781, 782, 0, 0, 779, + 762, 319, 0, 0, 768, 767, 760, 761, 760, 0, + 0, 0, 766, 765, 772, 763, 762, 769, 754, 750, + 0, 0, 747, 746, 757, 746, 757, 737, 736, 183, + 219, 228, 0, 267, 295, 0, 293, 294, 295, 306, + + 303, 317, 298, 311, 310, 313, 312, 314, 313, 315, + 0, 0, 318, 319, 324, 317, 318, 313, 327, 328, + 327, 329, 329, 330, 332, 332, 327, 328, 354, 345, + 330, 0, 343, 344, 351, 0, 343, 333, 334, 345, + 344, 347, 346, 348, 343, 0, 351, 352, 347, 350, + 345, 359, 360, 359, 361, 361, 362, 364, 364, 361, + 369, 361, 362, 368, 381, 390, 370, 368, 373, 374, + 369, 378, 379, 398, 393, 394, 0, 389, 0, 0, + 396, 384, 398, 386, 398, 401, 385, 403, 387, 405, + 389, 393, 395, 396, 0, 402, 403, 393, 413, 411, + + 396, 416, 414, 399, 400, 402, 427, 407, 411, 412, + 406, 408, 427, 428, 429, 417, 431, 419, 431, 423, + 435, 419, 437, 421, 426, 427, 0, 433, 434, 424, + 444, 442, 427, 447, 445, 446, 446, 443, 444, 450, + 450, 440, 0, 437, 444, 441, 441, 456, 457, 441, + 446, 447, 461, 449, 464, 451, 466, 466, 453, 0, + 464, 459, 466, 461, 463, 0, 0, 475, 476, 475, + 463, 480, 478, 466, 483, 477, 478, 468, 473, 0, + 485, 486, 0, 0, 474, 475, 476, 491, 478, 493, + 493, 0, 490, 485, 492, 487, 0, 0, 500, 501, + + 500, 488, 505, 503, 491, 508, 502, 494, 499, 500, + 0, 0, 497, 511, 513, 0, 498, 504, 505, 516, + 518, 519, 504, 500, 525, 502, 527, 0, 510, 516, + 518, 518, 520, 539, 534, 535, 523, 513, 514, 526, + 516, 517, 529, 530, 544, 528, 532, 533, 545, 546, + 526, 551, 528, 553, 0, 541, 543, 543, 545, 558, + 559, 547, 537, 538, 550, 540, 541, 553, 0, 561, + 562, 561, 553, 571, 568, 553, 554, 558, 0, 0, + 0, 0, 559, 0, 560, 556, 560, 566, 562, 568, + 568, 566, 567, 587, 0, 0, 588, 0, 0, 583, + + 584, 572, 584, 573, 574, 0, 0, 0, 578, 0, + 579, 578, 584, 580, 586, 582, 583, 603, 0, 0, + 604, 0, 0, 605, 588, 589, 594, 615, 593, 594, + 593, 594, 596, 591, 592, 603, 614, 600, 616, 602, + 622, 603, 616, 617, 613, 614, 610, 611, 626, 617, + 613, 614, 610, 611, 632, 618, 634, 620, 632, 633, + 629, 630, 625, 0, 0, 628, 633, 623, 0, 0, + 0, 640, 0, 0, 632, 637, 643, 639, 645, 636, + 641, 642, 643, 656, 657, 0, 0, 0, 643, 0, + 0, 0, 0, 648, 654, 650, 656, 651, 652, 665, + + 666, 655, 662, 671, 0, 658, 670, 674, 661, 676, + 663, 660, 662, 667, 668, 678, 679, 676, 685, 672, + 687, 674, 676, 677, 687, 688, 676, 675, 683, 683, + 0, 684, 685, 686, 687, 679, 682, 0, 0, 0, + 0, 684, 691, 692, 693, 694, 0, 0, 0, 0, + 0, 684, 705, 0, 708, 0, 709, 0, 698, 701, + 690, 713, 0, 714, 0, 0, 0, 713, 714, 702, + 0, 0, 716, 717, 0, 0, 719, 0, 0, 0, + 1273, 736, 740, 744, 748, 747, 752, 756, 755, 760, + 764, 763, 768, 772 + } ; -static const flex_int16_t yy_def[1191] = +static const flex_int16_t yy_def[1195] = { 0, - 1177, 1, 1177, 3, 1177, 5, 1178, 1178, 1179, 1179, - 1177, 1177, 1177, 1177, 1180, 1181, 1177, 1177, 1182, 1182, - 1182, 1182, 1182, 1182, 1177, 1177, 1177, 1177, 1183, 1184, - 1177, 1177, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1177, 1177, 1177, 1177, 1186, 1187, 1177, 1177, 1177, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1177, - 1177, 1189, 1177, 1177, 1190, 1177, 1177, 1180, 1177, 1181, - 1177, 1177, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, - - 1177, 1183, 1177, 1184, 1177, 1177, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1177, 1186, 1177, 1187, 1177, 1177, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1189, 1177, 1190, - 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1182, 1185, 1185, - - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1182, 1182, - 1182, 1182, 1182, 1182, 1182, 1182, 1185, 1185, 1185, 1185, - - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1182, 1182, 1182, 1182, 1182, 1182, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1182, 1182, 1182, 1182, 1182, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1182, 1182, - 1182, 1182, 1182, 1182, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1182, 1182, 1182, 1182, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1182, 1182, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1188, - - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1182, 1182, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - - 1188, 1188, 1182, 1182, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1182, 1182, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1188, 1188, 1188, 1188, 1188, - - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1182, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1182, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1188, 1182, 1185, 1185, - - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1188, 1188, 1188, 1188, 1188, 1188, 1188, - 1188, 1188, 1182, 1185, 1185, 1185, 1185, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1185, 1188, 1188, 1188, - 1188, 1188, 1188, 1188, 1188, 1188, 1182, 1185, 1185, 1185, - 1185, 1185, 1185, 1185, 1185, 1185, 1188, 1188, 1188, 1188, - 1188, 1185, 1185, 1185, 1185, 1185, 1185, 1188, 1188, 1188, - 1185, 1185, 1185, 1188, 1188, 1185, 0, 1177, 1177, 1177, - 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177 + 1181, 1, 1181, 3, 1181, 5, 1182, 1182, 1183, 1183, + 1181, 1181, 1181, 1181, 1184, 1185, 1181, 1181, 1186, 1186, + 1186, 1186, 1186, 1186, 1181, 1181, 1181, 1181, 1187, 1188, + 1181, 1181, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1181, 1181, 1181, 1181, 1190, 1191, 1181, 1181, 1181, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1181, + 1181, 1193, 1181, 1181, 1194, 1181, 1181, 1184, 1181, 1185, + 1181, 1181, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, + + 1181, 1187, 1181, 1188, 1181, 1181, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1181, 1190, 1181, 1191, 1181, 1181, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1193, 1181, 1194, + 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1189, 1189, + + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1186, + 1186, 1186, 1186, 1186, 1186, 1186, 1186, 1189, 1189, 1189, + + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1186, 1186, 1186, 1186, + 1186, 1186, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1186, 1186, 1186, 1186, 1186, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1186, 1186, 1186, 1186, 1186, 1186, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1186, 1186, + 1186, 1186, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1186, + 1186, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + + 1189, 1189, 1189, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1186, 1186, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + + 1192, 1192, 1192, 1192, 1192, 1192, 1186, 1186, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1186, 1186, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1192, + + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1186, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1186, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1192, 1192, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + + 1192, 1186, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1192, 1192, 1192, + 1192, 1192, 1192, 1192, 1192, 1192, 1186, 1189, 1189, 1189, + 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1189, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, 1192, + 1186, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, 1189, + 1192, 1192, 1192, 1192, 1192, 1189, 1189, 1189, 1189, 1189, + 1189, 1192, 1192, 1192, 1189, 1189, 1189, 1192, 1192, 1189, + 0, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, + 1181, 1181, 1181, 1181 + } ; -static const flex_int16_t yy_nxt[1310] = +static const flex_int16_t yy_nxt[1314] = { 0, 12, 13, 14, 13, 15, 16, 12, 12, 17, 18, 19, 19, 19, 19, 19, 20, 19, 19, 19, 19, @@ -824,32 +829,32 @@ static const flex_int16_t yy_nxt[1310] = 83, 84, 83, 84, 87, 91, 87, 94, 92, 98, 95, 101, 105, 101, 108, 106, 109, 113, 120, 110, 117, 111, 123, 124, 99, 114, 128, 132, 92, 126, - 130, 115, 121, 118, 116, 106, 131, 127, 136, 256, + 130, 115, 121, 118, 116, 106, 131, 127, 136, 257, 129, 133, 137, 142, 134, 144, 148, 144, 154, 149, - 257, 156, 138, 139, 151, 157, 152, 143, 164, 153, + 258, 156, 138, 139, 151, 157, 152, 143, 164, 153, 160, 158, 155, 165, 159, 170, 161, 175, 172, 149, - 177, 182, 183, 185, 178, 171, 173, 179, 767, 174, + 177, 182, 183, 185, 178, 171, 173, 179, 769, 174, 186, 187, 180, 176, 87, 181, 87, 91, 195, 204, 92, 196, 101, 105, 101, 205, 106, 209, 212, 215, - 227, 210, 219, 232, 248, 249, 216, 233, 211, 228, - 92, 144, 213, 144, 220, 148, 106, 246, 149, 253, - 260, 261, 271, 247, 265, 276, 272, 281, 331, 768, - 341, 332, 273, 254, 342, 266, 507, 346, 149, 508, - 407, 282, 277, 347, 375, 408, 376, 414, 429, 433, - 451, 377, 415, 430, 434, 452, 455, 472, 478, 486, - 769, 456, 473, 479, 487, 509, 770, 528, 510, 431, - 529, 531, 579, 530, 532, 535, 553, 533, 474, 554, - - 536, 555, 573, 576, 556, 574, 577, 591, 575, 578, - 596, 620, 580, 640, 771, 597, 621, 772, 641, 598, - 661, 709, 642, 592, 743, 662, 710, 773, 774, 744, - 775, 776, 777, 778, 779, 780, 781, 782, 783, 784, - 786, 788, 785, 787, 789, 790, 791, 792, 793, 794, + 227, 210, 219, 232, 234, 247, 216, 233, 211, 228, + 92, 248, 213, 235, 220, 144, 106, 144, 148, 249, + 250, 149, 254, 261, 262, 272, 266, 277, 282, 273, + 333, 770, 771, 334, 343, 274, 255, 267, 344, 348, + 510, 149, 283, 511, 278, 349, 377, 409, 378, 416, + 432, 436, 410, 379, 417, 433, 437, 454, 458, 475, + 481, 489, 455, 459, 476, 482, 490, 512, 772, 532, + 513, 434, 533, 535, 583, 534, 536, 539, 557, 537, + + 477, 558, 540, 559, 577, 580, 560, 578, 581, 595, + 579, 582, 600, 624, 584, 644, 773, 601, 625, 774, + 645, 602, 665, 713, 646, 596, 747, 666, 714, 775, + 776, 748, 777, 778, 779, 780, 781, 782, 783, 784, + 785, 786, 787, 788, 790, 792, 789, 791, 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, - 815, 816, 817, 819, 821, 818, 820, 822, 823, 824, - 825, 826, 827, 828, 829, 830, 831, 832, 833, 834, + 815, 816, 817, 818, 819, 820, 821, 823, 825, 822, + 824, 826, 827, 828, 829, 830, 831, 832, 833, 834, 835, 836, 837, 838, 839, 840, 841, 842, 843, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, @@ -888,73 +893,74 @@ static const flex_int16_t yy_nxt[1310] = 1145, 1146, 1147, 1148, 1149, 1150, 1151, 1152, 1153, 1154, 1155, 1156, 1157, 1158, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 1166, 1167, 1168, 1169, 1170, 1171, 1172, 1173, 1174, - 1175, 1176, 82, 82, 82, 82, 85, 85, 85, 85, - 88, 88, 88, 88, 90, 90, 93, 90, 102, 102, - 102, 102, 104, 104, 107, 104, 145, 145, 145, 145, - 147, 147, 150, 147, 188, 766, 765, 188, 190, 190, - 764, 190, 763, 762, 761, 760, 759, 758, 757, 756, - 755, 754, 753, 752, 751, 750, 749, 748, 747, 746, - 745, 742, 741, 740, 739, 738, 737, 736, 735, 734, - - 733, 732, 731, 730, 729, 728, 727, 726, 725, 724, - 723, 722, 721, 720, 719, 718, 717, 716, 715, 714, - 713, 712, 711, 708, 707, 706, 705, 704, 703, 702, - 701, 700, 699, 698, 697, 696, 695, 694, 693, 692, - 691, 690, 689, 688, 687, 686, 685, 684, 683, 682, - 681, 680, 679, 678, 677, 676, 675, 674, 673, 672, - 671, 670, 669, 668, 667, 666, 665, 664, 663, 660, - 659, 658, 657, 656, 655, 654, 653, 652, 651, 650, - 649, 648, 647, 646, 645, 644, 643, 639, 638, 637, - 636, 635, 634, 633, 632, 631, 630, 629, 628, 627, - - 626, 625, 624, 623, 622, 619, 618, 617, 616, 615, - 614, 613, 612, 611, 610, 609, 608, 607, 606, 605, - 604, 603, 602, 601, 600, 599, 595, 594, 593, 590, - 589, 588, 587, 586, 585, 584, 583, 582, 581, 572, - 571, 570, 569, 568, 567, 566, 565, 564, 563, 562, - 561, 560, 559, 558, 557, 552, 551, 550, 549, 548, - 547, 546, 545, 544, 543, 542, 541, 540, 539, 538, - 537, 534, 527, 526, 525, 524, 523, 522, 521, 520, - 519, 518, 517, 516, 515, 514, 513, 512, 511, 506, - 505, 504, 503, 502, 501, 500, 499, 498, 497, 496, - - 495, 494, 493, 492, 491, 490, 489, 488, 485, 484, - 483, 482, 481, 480, 477, 476, 475, 471, 470, 469, - 468, 467, 466, 465, 464, 463, 462, 461, 460, 459, - 458, 457, 454, 453, 450, 449, 448, 447, 446, 445, - 444, 443, 442, 441, 440, 439, 438, 437, 436, 435, - 432, 428, 427, 426, 425, 424, 423, 422, 421, 420, - 419, 418, 417, 416, 413, 412, 411, 410, 409, 406, - 405, 404, 403, 402, 401, 400, 399, 398, 397, 396, - 395, 394, 393, 392, 391, 390, 389, 388, 387, 386, - 385, 384, 383, 382, 381, 380, 379, 378, 374, 373, - - 372, 371, 370, 369, 368, 367, 366, 365, 364, 363, - 362, 361, 360, 359, 358, 357, 356, 355, 354, 353, - 352, 351, 350, 349, 348, 345, 344, 343, 340, 339, - 338, 337, 336, 335, 334, 333, 330, 329, 328, 327, - 326, 325, 324, 323, 322, 321, 320, 319, 318, 317, - 316, 315, 314, 313, 312, 311, 310, 309, 308, 307, - 306, 305, 304, 303, 302, 301, 300, 299, 298, 297, - 296, 295, 294, 293, 292, 291, 290, 289, 189, 288, - 287, 286, 285, 284, 283, 280, 279, 278, 275, 274, - 270, 269, 268, 267, 264, 263, 262, 259, 258, 255, - - 252, 251, 250, 245, 244, 243, 146, 242, 241, 240, - 239, 238, 237, 236, 235, 234, 231, 230, 229, 226, - 225, 224, 223, 222, 221, 218, 217, 214, 208, 207, - 206, 203, 202, 201, 200, 199, 103, 198, 197, 194, - 193, 192, 191, 89, 189, 184, 169, 168, 167, 166, - 163, 162, 146, 141, 140, 135, 125, 122, 119, 112, - 103, 100, 97, 96, 89, 1177, 86, 86, 11, 1177, - 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, - 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, - 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, - - 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177 + 1175, 1176, 1177, 1178, 1179, 1180, 82, 82, 82, 82, + 85, 85, 85, 85, 88, 88, 88, 88, 90, 90, + 93, 90, 102, 102, 102, 102, 104, 104, 107, 104, + 145, 145, 145, 145, 147, 147, 150, 147, 188, 768, + 767, 188, 190, 190, 766, 190, 765, 764, 763, 762, + 761, 760, 759, 758, 757, 756, 755, 754, 753, 752, + 751, 750, 749, 746, 745, 744, 743, 742, 741, 740, + + 739, 738, 737, 736, 735, 734, 733, 732, 731, 730, + 729, 728, 727, 726, 725, 724, 723, 722, 721, 720, + 719, 718, 717, 716, 715, 712, 711, 710, 709, 708, + 707, 706, 705, 704, 703, 702, 701, 700, 699, 698, + 697, 696, 695, 694, 693, 692, 691, 690, 689, 688, + 687, 686, 685, 684, 683, 682, 681, 680, 679, 678, + 677, 676, 675, 674, 673, 672, 671, 670, 669, 668, + 667, 664, 663, 662, 661, 660, 659, 658, 657, 656, + 655, 654, 653, 652, 651, 650, 649, 648, 647, 643, + 642, 641, 640, 639, 638, 637, 636, 635, 634, 633, + + 632, 631, 630, 629, 628, 627, 626, 623, 622, 621, + 620, 619, 618, 617, 616, 615, 614, 613, 612, 611, + 610, 609, 608, 607, 606, 605, 604, 603, 599, 598, + 597, 594, 593, 592, 591, 590, 589, 588, 587, 586, + 585, 576, 575, 574, 573, 572, 571, 570, 569, 568, + 567, 566, 565, 564, 563, 562, 561, 556, 555, 554, + 553, 552, 551, 550, 549, 548, 547, 546, 545, 544, + 543, 542, 541, 538, 531, 530, 529, 528, 527, 526, + 525, 524, 523, 522, 521, 520, 519, 518, 517, 516, + 515, 514, 509, 508, 507, 506, 505, 504, 503, 502, + + 501, 500, 499, 498, 497, 496, 495, 494, 493, 492, + 491, 488, 487, 486, 485, 484, 483, 480, 479, 478, + 474, 473, 472, 471, 470, 469, 468, 467, 466, 465, + 464, 463, 462, 461, 460, 457, 456, 453, 452, 451, + 450, 449, 448, 447, 446, 445, 444, 443, 442, 441, + 440, 439, 438, 435, 431, 430, 429, 428, 427, 426, + 425, 424, 423, 422, 421, 420, 419, 418, 415, 414, + 413, 412, 411, 408, 407, 406, 405, 404, 403, 402, + 401, 400, 399, 398, 397, 396, 395, 394, 393, 392, + 391, 390, 389, 388, 387, 386, 385, 384, 383, 382, + + 381, 380, 376, 375, 374, 373, 372, 371, 370, 369, + 368, 367, 366, 365, 364, 363, 362, 361, 360, 359, + 358, 357, 356, 355, 354, 353, 352, 351, 350, 347, + 346, 345, 342, 341, 340, 339, 338, 337, 336, 335, + 332, 331, 330, 329, 328, 327, 326, 325, 324, 323, + 322, 321, 320, 319, 318, 317, 316, 315, 314, 313, + 312, 311, 310, 309, 308, 307, 306, 305, 304, 303, + 302, 301, 300, 299, 298, 297, 296, 295, 294, 293, + 292, 291, 290, 189, 289, 288, 287, 286, 285, 284, + 281, 280, 279, 276, 275, 271, 270, 269, 268, 265, + + 264, 263, 260, 259, 256, 253, 252, 251, 246, 245, + 244, 146, 243, 242, 241, 240, 239, 238, 237, 236, + 231, 230, 229, 226, 225, 224, 223, 222, 221, 218, + 217, 214, 208, 207, 206, 203, 202, 201, 200, 199, + 103, 198, 197, 194, 193, 192, 191, 89, 189, 184, + 169, 168, 167, 166, 163, 162, 146, 141, 140, 135, + 125, 122, 119, 112, 103, 100, 97, 96, 89, 1181, + 86, 86, 11, 1181, 1181, 1181, 1181, 1181, 1181, 1181, + 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, + 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, + + 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, + 1181, 1181, 1181 } ; -static const flex_int16_t yy_chk[1310] = +static const flex_int16_t yy_chk[1314] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -976,130 +982,131 @@ static const flex_int16_t yy_chk[1310] = 44, 46, 48, 51, 46, 54, 59, 54, 63, 59, 161, 64, 48, 48, 62, 64, 62, 51, 68, 62, 65, 64, 63, 68, 64, 73, 65, 75, 74, 59, - 76, 77, 77, 79, 76, 73, 74, 76, 688, 74, + 76, 77, 77, 79, 76, 73, 74, 76, 690, 74, 79, 79, 76, 75, 87, 76, 87, 91, 98, 113, 91, 98, 101, 105, 101, 113, 105, 117, 118, 120, - 130, 117, 123, 134, 155, 155, 120, 134, 117, 130, - 91, 144, 118, 144, 123, 148, 105, 154, 148, 159, - 164, 164, 174, 154, 169, 177, 174, 181, 234, 690, - 245, 234, 174, 159, 245, 169, 414, 249, 148, 414, - 313, 181, 177, 249, 281, 313, 281, 319, 335, 338, - 356, 281, 319, 335, 338, 356, 360, 378, 382, 391, - 691, 360, 378, 382, 391, 415, 693, 433, 415, 335, - 433, 434, 481, 433, 434, 436, 455, 434, 378, 455, - - 436, 456, 478, 479, 456, 478, 479, 492, 478, 479, - 497, 521, 481, 544, 694, 497, 521, 695, 544, 497, - 565, 617, 544, 492, 658, 565, 617, 696, 697, 658, - 698, 699, 700, 701, 702, 703, 704, 705, 706, 709, - 710, 711, 709, 710, 712, 713, 714, 715, 716, 717, + 130, 117, 123, 134, 135, 154, 120, 134, 117, 130, + 91, 154, 118, 135, 123, 144, 105, 144, 148, 155, + 155, 148, 159, 164, 164, 174, 169, 177, 181, 174, + 235, 691, 692, 235, 246, 174, 159, 169, 246, 250, + 416, 148, 181, 416, 177, 250, 282, 314, 282, 320, + 337, 340, 314, 282, 320, 337, 340, 358, 362, 380, + 384, 393, 358, 362, 380, 384, 393, 417, 694, 436, + 417, 337, 436, 437, 484, 436, 437, 439, 458, 437, + + 380, 458, 439, 459, 481, 482, 459, 481, 482, 495, + 481, 482, 500, 525, 484, 548, 695, 500, 525, 697, + 548, 500, 569, 621, 548, 495, 662, 569, 621, 698, + 699, 662, 700, 701, 702, 703, 704, 705, 706, 707, + 708, 709, 710, 713, 714, 715, 713, 714, 716, 717, 718, 719, 720, 721, 722, 723, 724, 725, 726, 727, - 729, 730, 731, 733, 734, 735, 736, 737, 738, 739, - 740, 741, 743, 744, 745, 743, 744, 746, 747, 748, - 749, 750, 751, 752, 753, 754, 755, 756, 757, 758, + 728, 729, 730, 731, 733, 734, 735, 737, 738, 739, + 740, 741, 742, 743, 744, 745, 747, 748, 749, 747, + 748, 750, 751, 752, 753, 754, 755, 756, 757, 758, 759, 760, 761, 762, 763, 764, 765, 766, 767, 768, - 769, 770, 771, 772, 774, 777, 778, 779, 780, 781, - 782, 783, 784, 785, 786, 787, 788, 789, 790, 792, - 793, 794, 795, 796, 797, 798, 799, 800, 801, 802, + 769, 770, 771, 772, 773, 774, 775, 776, 778, 781, + 782, 783, 784, 785, 786, 787, 788, 789, 790, 791, + 792, 793, 794, 796, 797, 798, 799, 800, 801, 802, 803, 804, 805, 806, 807, 808, 809, 810, 811, 812, 813, 814, 815, 816, 817, 818, 819, 820, 821, 822, - 824, 825, 826, 827, 828, 829, 830, 831, 832, 833, - 834, 835, 836, 837, 838, 840, 841, 842, 843, 844, + 823, 824, 825, 826, 828, 829, 830, 831, 832, 833, + 834, 835, 836, 837, 838, 839, 840, 841, 842, 844, 845, 846, 847, 848, 849, 850, 851, 852, 853, 854, - 855, 857, 858, 859, 860, 861, 864, 865, 866, 867, - 868, 869, 870, 871, 872, 873, 874, 875, 877, 878, - - 881, 882, 883, 884, 885, 886, 887, 889, 890, 891, - 892, 895, 896, 897, 898, 899, 900, 901, 902, 903, - 904, 905, 906, 909, 910, 911, 913, 914, 915, 916, - 917, 918, 919, 920, 921, 922, 923, 925, 926, 927, - 928, 929, 930, 931, 932, 933, 934, 935, 936, 937, + 855, 856, 857, 858, 859, 861, 862, 863, 864, 865, + 868, 869, 870, 871, 872, 873, 874, 875, 876, 877, + + 878, 879, 881, 882, 885, 886, 887, 888, 889, 890, + 891, 893, 894, 895, 896, 899, 900, 901, 902, 903, + 904, 905, 906, 907, 908, 909, 910, 913, 914, 915, + 917, 918, 919, 920, 921, 922, 923, 924, 925, 926, + 927, 929, 930, 931, 932, 933, 934, 935, 936, 937, 938, 939, 940, 941, 942, 943, 944, 945, 946, 947, - 948, 949, 950, 952, 953, 954, 955, 956, 957, 958, - 959, 960, 961, 962, 963, 964, 966, 967, 968, 969, - 970, 971, 972, 973, 974, 979, 981, 982, 983, 984, - 985, 986, 987, 987, 988, 989, 990, 993, 996, 997, + 948, 949, 950, 951, 952, 953, 954, 956, 957, 958, + 959, 960, 961, 962, 963, 964, 965, 966, 967, 968, + 970, 971, 972, 973, 974, 975, 976, 977, 978, 983, + 985, 986, 987, 988, 989, 990, 991, 991, 992, 993, - 998, 999, 1000, 1001, 1005, 1007, 1008, 1009, 1010, 1011, - 1012, 1013, 1014, 1017, 1020, 1021, 1022, 1023, 1024, 1025, + 994, 997, 1000, 1001, 1002, 1003, 1004, 1005, 1009, 1011, + 1012, 1013, 1014, 1015, 1016, 1017, 1018, 1021, 1024, 1025, 1026, 1027, 1028, 1029, 1030, 1031, 1032, 1033, 1034, 1035, 1036, 1037, 1038, 1039, 1040, 1041, 1042, 1043, 1044, 1045, 1046, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 1054, 1055, - 1056, 1057, 1058, 1059, 1062, 1063, 1064, 1068, 1071, 1072, - 1073, 1074, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1085, - 1090, 1091, 1092, 1093, 1094, 1095, 1096, 1097, 1098, 1099, - 1100, 1102, 1103, 1104, 1105, 1106, 1107, 1108, 1109, 1110, + 1056, 1057, 1058, 1059, 1060, 1061, 1062, 1063, 1066, 1067, + 1068, 1072, 1075, 1076, 1077, 1078, 1079, 1080, 1081, 1082, + 1083, 1084, 1085, 1089, 1094, 1095, 1096, 1097, 1098, 1099, + 1100, 1101, 1102, 1103, 1104, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 1113, 1114, 1115, 1116, 1117, 1118, 1119, 1120, - 1121, 1122, 1123, 1124, 1125, 1126, 1128, 1129, 1130, 1131, - 1132, 1133, 1138, 1139, 1140, 1141, 1142, 1148, 1149, 1151, - 1153, 1155, 1156, 1157, 1158, 1160, 1164, 1165, 1166, 1169, - 1170, 1173, 1178, 1178, 1178, 1178, 1179, 1179, 1179, 1179, - 1180, 1180, 1180, 1180, 1181, 1181, 1182, 1181, 1183, 1183, - 1183, 1183, 1184, 1184, 1185, 1184, 1186, 1186, 1186, 1186, - 1187, 1187, 1188, 1187, 1189, 687, 686, 1189, 1190, 1190, - 685, 1190, 684, 683, 682, 681, 680, 679, 676, 675, - 674, 673, 672, 671, 670, 669, 665, 664, 663, 662, - 661, 657, 656, 653, 652, 651, 650, 649, 648, 647, - - 646, 644, 643, 641, 640, 639, 636, 635, 634, 633, - 632, 631, 630, 629, 628, 627, 626, 624, 623, 622, - 621, 620, 619, 616, 615, 614, 613, 612, 611, 610, - 609, 608, 607, 606, 605, 604, 603, 602, 601, 599, - 597, 596, 595, 594, 593, 592, 591, 590, 589, 588, - 587, 586, 585, 584, 583, 580, 579, 578, 577, 576, - 575, 574, 573, 572, 571, 570, 569, 568, 566, 564, - 563, 562, 561, 560, 559, 558, 557, 556, 555, 554, - 553, 551, 550, 548, 547, 546, 545, 543, 542, 541, - 540, 539, 538, 536, 535, 533, 532, 531, 530, 529, - - 528, 526, 525, 524, 522, 520, 519, 518, 517, 516, - 515, 514, 513, 510, 509, 508, 507, 506, 505, 504, - 503, 502, 501, 500, 499, 498, 496, 495, 493, 491, - 490, 489, 488, 487, 486, 485, 484, 483, 482, 476, - 475, 474, 473, 472, 467, 466, 465, 464, 463, 462, - 461, 460, 459, 458, 457, 454, 452, 451, 450, 449, - 447, 446, 445, 444, 443, 442, 441, 440, 439, 438, - 437, 435, 432, 431, 430, 429, 428, 427, 426, 425, - 424, 423, 422, 421, 420, 419, 418, 417, 416, 413, - 412, 411, 409, 408, 407, 405, 404, 403, 402, 401, - - 400, 399, 398, 397, 396, 395, 394, 393, 390, 388, - 387, 386, 385, 383, 381, 380, 379, 377, 376, 375, - 374, 373, 372, 371, 370, 369, 368, 367, 366, 365, - 364, 363, 359, 357, 355, 354, 353, 352, 351, 349, - 348, 347, 346, 345, 344, 343, 342, 341, 340, 339, - 337, 334, 333, 332, 331, 330, 329, 327, 326, 324, - 323, 322, 321, 320, 318, 317, 316, 315, 314, 312, - 311, 310, 309, 308, 307, 306, 305, 304, 303, 302, - 301, 300, 299, 298, 297, 296, 294, 293, 291, 290, - 289, 288, 287, 286, 285, 284, 283, 282, 279, 278, - - 276, 274, 273, 272, 271, 270, 269, 267, 266, 265, - 264, 263, 262, 261, 260, 259, 258, 257, 256, 255, - 254, 253, 252, 251, 250, 248, 247, 246, 244, 242, - 241, 240, 239, 238, 236, 235, 233, 232, 231, 230, - 229, 228, 227, 226, 225, 224, 223, 222, 221, 220, - 219, 218, 217, 216, 215, 214, 213, 212, 211, 210, - 209, 208, 207, 206, 205, 204, 203, 202, 201, 200, - 198, 197, 196, 195, 194, 193, 192, 191, 189, 187, - 186, 185, 184, 183, 182, 180, 179, 178, 176, 175, - 173, 172, 171, 170, 168, 167, 166, 163, 162, 160, - - 158, 157, 156, 153, 152, 151, 145, 143, 142, 141, - 140, 139, 138, 137, 136, 135, 133, 132, 131, 129, - 128, 127, 126, 125, 124, 122, 121, 119, 116, 115, - 114, 112, 111, 110, 109, 108, 102, 100, 99, 97, - 96, 95, 94, 88, 83, 78, 72, 71, 70, 69, - 67, 66, 56, 50, 49, 47, 42, 40, 38, 35, - 29, 24, 22, 21, 15, 11, 10, 9, 1177, 1177, - 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, - 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, - 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, - - 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177, 1177 + 1121, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, + 1132, 1133, 1134, 1135, 1136, 1137, 1142, 1143, 1144, 1145, + 1146, 1152, 1153, 1155, 1157, 1159, 1160, 1161, 1162, 1164, + 1168, 1169, 1170, 1173, 1174, 1177, 1182, 1182, 1182, 1182, + 1183, 1183, 1183, 1183, 1184, 1184, 1184, 1184, 1185, 1185, + 1186, 1185, 1187, 1187, 1187, 1187, 1188, 1188, 1189, 1188, + 1190, 1190, 1190, 1190, 1191, 1191, 1192, 1191, 1193, 689, + 688, 1193, 1194, 1194, 687, 1194, 686, 685, 684, 683, + 680, 679, 678, 677, 676, 675, 674, 673, 669, 668, + 667, 666, 665, 661, 660, 657, 656, 655, 654, 653, + + 652, 651, 650, 648, 647, 645, 644, 643, 640, 639, + 638, 637, 636, 635, 634, 633, 632, 631, 630, 628, + 627, 626, 625, 624, 623, 620, 619, 618, 617, 616, + 615, 614, 613, 612, 611, 610, 609, 608, 607, 606, + 605, 603, 601, 600, 599, 598, 597, 596, 595, 594, + 593, 592, 591, 590, 589, 588, 587, 584, 583, 582, + 581, 580, 579, 578, 577, 576, 575, 574, 573, 572, + 570, 568, 567, 566, 565, 564, 563, 562, 561, 560, + 559, 558, 557, 555, 554, 552, 551, 550, 549, 547, + 546, 545, 544, 543, 542, 540, 539, 537, 536, 535, + + 534, 533, 532, 530, 529, 528, 526, 524, 522, 521, + 520, 519, 518, 517, 516, 513, 512, 511, 510, 509, + 508, 507, 506, 505, 504, 503, 502, 501, 499, 498, + 496, 494, 493, 492, 491, 490, 489, 488, 487, 486, + 485, 479, 478, 477, 476, 475, 470, 469, 468, 467, + 466, 465, 464, 463, 462, 461, 460, 457, 455, 454, + 453, 452, 450, 449, 448, 447, 446, 445, 444, 443, + 442, 441, 440, 438, 435, 434, 433, 432, 431, 430, + 429, 428, 427, 426, 425, 424, 423, 422, 421, 420, + 419, 418, 415, 414, 413, 411, 410, 409, 407, 406, + + 405, 404, 403, 402, 401, 400, 399, 398, 397, 396, + 395, 392, 390, 389, 388, 387, 385, 383, 382, 381, + 379, 378, 377, 376, 375, 374, 373, 372, 371, 370, + 369, 368, 367, 366, 365, 361, 359, 357, 356, 355, + 354, 353, 351, 350, 349, 348, 347, 346, 345, 344, + 343, 342, 341, 339, 336, 335, 334, 333, 332, 331, + 330, 328, 327, 325, 324, 323, 322, 321, 319, 318, + 317, 316, 315, 313, 312, 311, 310, 309, 308, 307, + 306, 305, 304, 303, 302, 301, 300, 299, 298, 297, + 295, 294, 292, 291, 290, 289, 288, 287, 286, 285, + + 284, 283, 280, 279, 277, 275, 274, 273, 272, 271, + 270, 268, 267, 266, 265, 264, 263, 262, 261, 260, + 259, 258, 257, 256, 255, 254, 253, 252, 251, 249, + 248, 247, 245, 243, 242, 241, 240, 239, 237, 236, + 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, + 224, 223, 222, 221, 220, 219, 218, 217, 216, 215, + 214, 213, 212, 211, 210, 209, 208, 207, 206, 205, + 204, 203, 202, 201, 200, 198, 197, 196, 195, 194, + 193, 192, 191, 189, 187, 186, 185, 184, 183, 182, + 180, 179, 178, 176, 175, 173, 172, 171, 170, 168, + + 167, 166, 163, 162, 160, 158, 157, 156, 153, 152, + 151, 145, 143, 142, 141, 140, 139, 138, 137, 136, + 133, 132, 131, 129, 128, 127, 126, 125, 124, 122, + 121, 119, 116, 115, 114, 112, 111, 110, 109, 108, + 102, 100, 99, 97, 96, 95, 94, 88, 83, 78, + 72, 71, 70, 69, 67, 66, 56, 50, 49, 47, + 42, 40, 38, 35, 29, 24, 22, 21, 15, 11, + 10, 9, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, + 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, + 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, + + 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, 1181, + 1181, 1181, 1181 } ; static yy_state_type yy_last_accepting_state; @@ -1116,8 +1123,8 @@ int yy_flex_debug = 0; #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; -#line 1 "test_spec_scan.l" -#line 2 "test_spec_scan.l" +#line 1 "src/bin/pgaftest/test_spec_scan.l" +#line 2 "src/bin/pgaftest/test_spec_scan.l" /* * src/bin/pgaftest/test_spec_scan.l * Flex lexer for .pgaf test specification files. @@ -1194,9 +1201,9 @@ static char *pgaf_strdup(const char *s) * call flex's static input() function. */ static void pgaf_read_raw_block(void); -#line 1197 "test_spec_scan.c" +#line 1204 "src/bin/pgaftest/test_spec_scan.c" -#line 1199 "test_spec_scan.c" +#line 1206 "src/bin/pgaftest/test_spec_scan.c" #define INITIAL 0 #define CLUSTER_BODY 1 @@ -1415,10 +1422,10 @@ YY_DECL } { -#line 89 "test_spec_scan.l" +#line 89 "src/bin/pgaftest/test_spec_scan.l" -#line 1421 "test_spec_scan.c" +#line 1428 "src/bin/pgaftest/test_spec_scan.c" while ( /*CONSTCOND*/1 ) /* loops until end-of-file is reached */ { @@ -1445,13 +1452,13 @@ YY_DECL while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 1178 ) + if ( yy_current_state >= 1182 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } - while ( yy_current_state != 1177 ); + while ( yy_current_state != 1181 ); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); @@ -1473,62 +1480,62 @@ YY_DECL case 1: YY_RULE_SETUP -#line 91 "test_spec_scan.l" +#line 91 "src/bin/pgaftest/test_spec_scan.l" { /* comment */ } YY_BREAK case 2: YY_RULE_SETUP -#line 93 "test_spec_scan.l" +#line 93 "src/bin/pgaftest/test_spec_scan.l" { pgaf_next_brace_is_cluster = 1; return T_CLUSTER; } YY_BREAK case 3: YY_RULE_SETUP -#line 94 "test_spec_scan.l" +#line 94 "src/bin/pgaftest/test_spec_scan.l" { return T_MONITOR; } YY_BREAK case 4: YY_RULE_SETUP -#line 95 "test_spec_scan.l" +#line 95 "src/bin/pgaftest/test_spec_scan.l" { return T_NODE; } YY_BREAK case 5: YY_RULE_SETUP -#line 96 "test_spec_scan.l" +#line 96 "src/bin/pgaftest/test_spec_scan.l" { return T_CITUS_COORDINATOR; } YY_BREAK case 6: YY_RULE_SETUP -#line 97 "test_spec_scan.l" +#line 97 "src/bin/pgaftest/test_spec_scan.l" { return T_CITUS_WORKER; } YY_BREAK case 7: YY_RULE_SETUP -#line 99 "test_spec_scan.l" +#line 99 "src/bin/pgaftest/test_spec_scan.l" { pgaf_next_brace_is_step = 1; return T_SETUP; } YY_BREAK case 8: YY_RULE_SETUP -#line 100 "test_spec_scan.l" +#line 100 "src/bin/pgaftest/test_spec_scan.l" { pgaf_next_brace_is_step = 1; return T_TEARDOWN; } YY_BREAK case 9: YY_RULE_SETUP -#line 101 "test_spec_scan.l" +#line 101 "src/bin/pgaftest/test_spec_scan.l" { pgaf_next_brace_is_step = 1; return T_STEP; } YY_BREAK case 10: YY_RULE_SETUP -#line 102 "test_spec_scan.l" +#line 102 "src/bin/pgaftest/test_spec_scan.l" { return T_SEQUENCE; } YY_BREAK case 11: YY_RULE_SETUP -#line 104 "test_spec_scan.l" +#line 104 "src/bin/pgaftest/test_spec_scan.l" { return T_EQUALS; } YY_BREAK case 12: YY_RULE_SETUP -#line 106 "test_spec_scan.l" +#line 106 "src/bin/pgaftest/test_spec_scan.l" { yylval.ival = atoi(yytext); return T_INTEGER; @@ -1536,7 +1543,7 @@ YY_RULE_SETUP YY_BREAK case 13: YY_RULE_SETUP -#line 111 "test_spec_scan.l" +#line 111 "src/bin/pgaftest/test_spec_scan.l" { yylval.str = pgaf_strdup(yytext); return T_IDENT; @@ -1545,7 +1552,7 @@ YY_RULE_SETUP case 14: /* rule 14 can match eol */ YY_RULE_SETUP -#line 116 "test_spec_scan.l" +#line 116 "src/bin/pgaftest/test_spec_scan.l" { yytext[yyleng - 1] = '\0'; yylval.str = pgaf_strdup(yytext + 1); @@ -1554,7 +1561,7 @@ YY_RULE_SETUP YY_BREAK case 15: YY_RULE_SETUP -#line 122 "test_spec_scan.l" +#line 122 "src/bin/pgaftest/test_spec_scan.l" { if (pgaf_next_brace_is_step) { @@ -1576,17 +1583,17 @@ YY_RULE_SETUP case 16: /* rule 16 can match eol */ YY_RULE_SETUP -#line 140 "test_spec_scan.l" +#line 140 "src/bin/pgaftest/test_spec_scan.l" { pgaf_line_number++; } YY_BREAK case 17: YY_RULE_SETUP -#line 141 "test_spec_scan.l" +#line 141 "src/bin/pgaftest/test_spec_scan.l" { /* whitespace */ } YY_BREAK case 18: YY_RULE_SETUP -#line 143 "test_spec_scan.l" +#line 143 "src/bin/pgaftest/test_spec_scan.l" { fprintf(stderr, "pgaftest: unexpected character '%c' at line %d\n", yytext[0], pgaf_line_number); @@ -1594,234 +1601,239 @@ YY_RULE_SETUP YY_BREAK case 19: YY_RULE_SETUP -#line 148 "test_spec_scan.l" +#line 148 "src/bin/pgaftest/test_spec_scan.l" { /* comment */ } YY_BREAK case 20: /* rule 20 can match eol */ YY_RULE_SETUP -#line 149 "test_spec_scan.l" +#line 149 "src/bin/pgaftest/test_spec_scan.l" { pgaf_line_number++; } YY_BREAK case 21: YY_RULE_SETUP -#line 150 "test_spec_scan.l" +#line 150 "src/bin/pgaftest/test_spec_scan.l" { /* whitespace */ } YY_BREAK case 22: YY_RULE_SETUP -#line 152 "test_spec_scan.l" +#line 152 "src/bin/pgaftest/test_spec_scan.l" { return T_MONITOR; } YY_BREAK case 23: YY_RULE_SETUP -#line 153 "test_spec_scan.l" +#line 153 "src/bin/pgaftest/test_spec_scan.l" { return T_IMAGE_TARGET; } YY_BREAK case 24: YY_RULE_SETUP -#line 154 "test_spec_scan.l" +#line 154 "src/bin/pgaftest/test_spec_scan.l" { return T_IMAGE; } YY_BREAK case 25: YY_RULE_SETUP -#line 155 "test_spec_scan.l" +#line 155 "src/bin/pgaftest/test_spec_scan.l" { return T_SSL; } YY_BREAK case 26: YY_RULE_SETUP -#line 156 "test_spec_scan.l" +#line 156 "src/bin/pgaftest/test_spec_scan.l" { return T_AUTH_METHOD; } YY_BREAK case 27: YY_RULE_SETUP -#line 157 "test_spec_scan.l" +#line 157 "src/bin/pgaftest/test_spec_scan.l" { return T_AUTH; } YY_BREAK case 28: YY_RULE_SETUP -#line 158 "test_spec_scan.l" +#line 158 "src/bin/pgaftest/test_spec_scan.l" { return T_FORMATION; } YY_BREAK case 29: YY_RULE_SETUP -#line 159 "test_spec_scan.l" +#line 159 "src/bin/pgaftest/test_spec_scan.l" { return T_NUM_SYNC; } YY_BREAK case 30: YY_RULE_SETUP -#line 160 "test_spec_scan.l" +#line 160 "src/bin/pgaftest/test_spec_scan.l" { return T_NODE; } YY_BREAK case 31: YY_RULE_SETUP -#line 162 "test_spec_scan.l" +#line 162 "src/bin/pgaftest/test_spec_scan.l" { return T_COORDINATOR; } YY_BREAK case 32: YY_RULE_SETUP -#line 163 "test_spec_scan.l" +#line 163 "src/bin/pgaftest/test_spec_scan.l" { return T_WORKER; } YY_BREAK case 33: YY_RULE_SETUP -#line 164 "test_spec_scan.l" +#line 164 "src/bin/pgaftest/test_spec_scan.l" { return T_ASYNC; } YY_BREAK case 34: YY_RULE_SETUP -#line 165 "test_spec_scan.l" +#line 165 "src/bin/pgaftest/test_spec_scan.l" { return T_NO_MONITOR; } YY_BREAK case 35: YY_RULE_SETUP -#line 166 "test_spec_scan.l" +#line 166 "src/bin/pgaftest/test_spec_scan.l" { return T_PASSWORD; } YY_BREAK case 36: YY_RULE_SETUP -#line 167 "test_spec_scan.l" +#line 167 "src/bin/pgaftest/test_spec_scan.l" { return T_MONITOR_PASSWORD; } YY_BREAK case 37: YY_RULE_SETUP -#line 168 "test_spec_scan.l" +#line 168 "src/bin/pgaftest/test_spec_scan.l" { return T_LAUNCH; } YY_BREAK case 38: YY_RULE_SETUP -#line 169 "test_spec_scan.l" +#line 169 "src/bin/pgaftest/test_spec_scan.l" { return T_CREATE; } YY_BREAK case 39: YY_RULE_SETUP -#line 170 "test_spec_scan.l" +#line 170 "src/bin/pgaftest/test_spec_scan.l" { return T_DEFERRED; } YY_BREAK case 40: YY_RULE_SETUP -#line 171 "test_spec_scan.l" +#line 171 "src/bin/pgaftest/test_spec_scan.l" { return T_IMMEDIATE; } YY_BREAK case 41: YY_RULE_SETUP -#line 172 "test_spec_scan.l" +#line 172 "src/bin/pgaftest/test_spec_scan.l" { return T_FALSE; } YY_BREAK case 42: YY_RULE_SETUP -#line 173 "test_spec_scan.l" +#line 173 "src/bin/pgaftest/test_spec_scan.l" { return T_TRUE; } YY_BREAK case 43: YY_RULE_SETUP -#line 174 "test_spec_scan.l" +#line 174 "src/bin/pgaftest/test_spec_scan.l" { return T_AND; } YY_BREAK case 44: YY_RULE_SETUP -#line 175 "test_spec_scan.l" +#line 175 "src/bin/pgaftest/test_spec_scan.l" { return T_INITIALLY; } YY_BREAK case 45: YY_RULE_SETUP -#line 176 "test_spec_scan.l" +#line 176 "src/bin/pgaftest/test_spec_scan.l" { return T_STOPPED; } YY_BREAK case 46: YY_RULE_SETUP -#line 177 "test_spec_scan.l" +#line 177 "src/bin/pgaftest/test_spec_scan.l" { return T_VOLUME; } YY_BREAK case 47: YY_RULE_SETUP -#line 178 "test_spec_scan.l" +#line 178 "src/bin/pgaftest/test_spec_scan.l" { return T_LISTEN; } YY_BREAK case 48: YY_RULE_SETUP -#line 179 "test_spec_scan.l" +#line 179 "src/bin/pgaftest/test_spec_scan.l" { return T_CITUS_SECONDARY; } YY_BREAK case 49: YY_RULE_SETUP -#line 180 "test_spec_scan.l" +#line 180 "src/bin/pgaftest/test_spec_scan.l" { return T_CANDIDATE_PRIORITY; } YY_BREAK case 50: YY_RULE_SETUP -#line 181 "test_spec_scan.l" -{ return T_GROUP; } +#line 181 "src/bin/pgaftest/test_spec_scan.l" +{ return T_REGION; } YY_BREAK case 51: YY_RULE_SETUP -#line 182 "test_spec_scan.l" -{ return T_PORT; } +#line 182 "src/bin/pgaftest/test_spec_scan.l" +{ return T_GROUP; } YY_BREAK case 52: YY_RULE_SETUP -#line 183 "test_spec_scan.l" -{ return T_CITUS_CLUSTER_NAME; } +#line 183 "src/bin/pgaftest/test_spec_scan.l" +{ return T_PORT; } YY_BREAK case 53: YY_RULE_SETUP -#line 184 "test_spec_scan.l" -{ return T_DEBIAN_CLUSTER; } +#line 184 "src/bin/pgaftest/test_spec_scan.l" +{ return T_CITUS_CLUSTER_NAME; } YY_BREAK case 54: YY_RULE_SETUP -#line 185 "test_spec_scan.l" -{ return T_REPLICATION_QUORUM; } +#line 185 "src/bin/pgaftest/test_spec_scan.l" +{ return T_DEBIAN_CLUSTER; } YY_BREAK case 55: YY_RULE_SETUP -#line 186 "test_spec_scan.l" -{ return T_REPLICATION_PASSWORD; } +#line 186 "src/bin/pgaftest/test_spec_scan.l" +{ return T_REPLICATION_QUORUM; } YY_BREAK case 56: YY_RULE_SETUP -#line 187 "test_spec_scan.l" -{ return T_EXTENSION_VERSION; } +#line 187 "src/bin/pgaftest/test_spec_scan.l" +{ return T_REPLICATION_PASSWORD; } YY_BREAK case 57: YY_RULE_SETUP -#line 188 "test_spec_scan.l" -{ return T_BIND_SOURCE; } +#line 188 "src/bin/pgaftest/test_spec_scan.l" +{ return T_EXTENSION_VERSION; } YY_BREAK case 58: YY_RULE_SETUP -#line 190 "test_spec_scan.l" -{ return T_EQUALS; } +#line 189 "src/bin/pgaftest/test_spec_scan.l" +{ return T_BIND_SOURCE; } YY_BREAK case 59: YY_RULE_SETUP -#line 192 "test_spec_scan.l" +#line 191 "src/bin/pgaftest/test_spec_scan.l" +{ return T_EQUALS; } + YY_BREAK +case 60: +YY_RULE_SETUP +#line 193 "src/bin/pgaftest/test_spec_scan.l" { yylval.ival = atoi(yytext); return T_INTEGER; } YY_BREAK -case 60: -/* rule 60 can match eol */ +case 61: +/* rule 61 can match eol */ YY_RULE_SETUP -#line 197 "test_spec_scan.l" +#line 198 "src/bin/pgaftest/test_spec_scan.l" { yytext[yyleng - 1] = '\0'; yylval.str = pgaf_strdup(yytext + 1); return T_STRING; } YY_BREAK -case 61: +case 62: YY_RULE_SETUP -#line 203 "test_spec_scan.l" +#line 204 "src/bin/pgaftest/test_spec_scan.l" { pgaf_cluster_depth++; return T_LBRACE; } YY_BREAK -case 62: +case 63: YY_RULE_SETUP -#line 208 "test_spec_scan.l" +#line 209 "src/bin/pgaftest/test_spec_scan.l" { pgaf_cluster_depth--; if (pgaf_cluster_depth == 0) @@ -1829,426 +1841,426 @@ YY_RULE_SETUP return T_RBRACE; } YY_BREAK -case 63: -YY_RULE_SETUP -#line 215 "test_spec_scan.l" -{ return T_FS_INIT; } - YY_BREAK case 64: YY_RULE_SETUP -#line 216 "test_spec_scan.l" -{ return T_FS_SINGLE; } +#line 216 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_INIT; } YY_BREAK case 65: YY_RULE_SETUP -#line 217 "test_spec_scan.l" -{ return T_FS_PRIMARY; } +#line 217 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_SINGLE; } YY_BREAK case 66: YY_RULE_SETUP -#line 218 "test_spec_scan.l" -{ return T_FS_WAIT_PRIMARY; } +#line 218 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_PRIMARY; } YY_BREAK case 67: YY_RULE_SETUP -#line 219 "test_spec_scan.l" +#line 219 "src/bin/pgaftest/test_spec_scan.l" { return T_FS_WAIT_PRIMARY; } YY_BREAK case 68: YY_RULE_SETUP -#line 220 "test_spec_scan.l" -{ return T_FS_WAIT_STANDBY; } +#line 220 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_WAIT_PRIMARY; } YY_BREAK case 69: YY_RULE_SETUP -#line 221 "test_spec_scan.l" +#line 221 "src/bin/pgaftest/test_spec_scan.l" { return T_FS_WAIT_STANDBY; } YY_BREAK case 70: YY_RULE_SETUP -#line 222 "test_spec_scan.l" -{ return T_FS_DEMOTED; } +#line 222 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_WAIT_STANDBY; } YY_BREAK case 71: YY_RULE_SETUP -#line 223 "test_spec_scan.l" -{ return T_FS_DEMOTE_TIMEOUT; } +#line 223 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_DEMOTED; } YY_BREAK case 72: YY_RULE_SETUP -#line 224 "test_spec_scan.l" +#line 224 "src/bin/pgaftest/test_spec_scan.l" { return T_FS_DEMOTE_TIMEOUT; } YY_BREAK case 73: YY_RULE_SETUP -#line 225 "test_spec_scan.l" -{ return T_FS_DRAINING; } +#line 225 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_DEMOTE_TIMEOUT; } YY_BREAK case 74: YY_RULE_SETUP -#line 226 "test_spec_scan.l" -{ return T_FS_SECONDARY; } +#line 226 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_DRAINING; } YY_BREAK case 75: YY_RULE_SETUP -#line 227 "test_spec_scan.l" -{ return T_FS_CATCHINGUP; } +#line 227 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_SECONDARY; } YY_BREAK case 76: YY_RULE_SETUP -#line 228 "test_spec_scan.l" -{ return T_FS_PREP_PROMOTION; } +#line 228 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_CATCHINGUP; } YY_BREAK case 77: YY_RULE_SETUP -#line 229 "test_spec_scan.l" +#line 229 "src/bin/pgaftest/test_spec_scan.l" { return T_FS_PREP_PROMOTION; } YY_BREAK case 78: YY_RULE_SETUP -#line 230 "test_spec_scan.l" -{ return T_FS_STOP_REPLICATION; } +#line 230 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_PREP_PROMOTION; } YY_BREAK case 79: YY_RULE_SETUP -#line 231 "test_spec_scan.l" +#line 231 "src/bin/pgaftest/test_spec_scan.l" { return T_FS_STOP_REPLICATION; } YY_BREAK case 80: YY_RULE_SETUP -#line 232 "test_spec_scan.l" -{ return T_FS_MAINTENANCE; } +#line 232 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_STOP_REPLICATION; } YY_BREAK case 81: YY_RULE_SETUP -#line 233 "test_spec_scan.l" -{ return T_FS_JOIN_PRIMARY; } +#line 233 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_MAINTENANCE; } YY_BREAK case 82: YY_RULE_SETUP -#line 234 "test_spec_scan.l" +#line 234 "src/bin/pgaftest/test_spec_scan.l" { return T_FS_JOIN_PRIMARY; } YY_BREAK case 83: YY_RULE_SETUP -#line 235 "test_spec_scan.l" -{ return T_FS_APPLY_SETTINGS; } +#line 235 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_JOIN_PRIMARY; } YY_BREAK case 84: YY_RULE_SETUP -#line 236 "test_spec_scan.l" +#line 236 "src/bin/pgaftest/test_spec_scan.l" { return T_FS_APPLY_SETTINGS; } YY_BREAK case 85: YY_RULE_SETUP -#line 237 "test_spec_scan.l" -{ return T_FS_PREPARE_MAINTENANCE; } +#line 237 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_APPLY_SETTINGS; } YY_BREAK case 86: YY_RULE_SETUP -#line 238 "test_spec_scan.l" +#line 238 "src/bin/pgaftest/test_spec_scan.l" { return T_FS_PREPARE_MAINTENANCE; } YY_BREAK case 87: YY_RULE_SETUP -#line 239 "test_spec_scan.l" -{ return T_FS_WAIT_MAINTENANCE; } +#line 239 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_PREPARE_MAINTENANCE; } YY_BREAK case 88: YY_RULE_SETUP -#line 240 "test_spec_scan.l" +#line 240 "src/bin/pgaftest/test_spec_scan.l" { return T_FS_WAIT_MAINTENANCE; } YY_BREAK case 89: YY_RULE_SETUP -#line 241 "test_spec_scan.l" -{ return T_FS_REPORT_LSN; } +#line 241 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_WAIT_MAINTENANCE; } YY_BREAK case 90: YY_RULE_SETUP -#line 242 "test_spec_scan.l" +#line 242 "src/bin/pgaftest/test_spec_scan.l" { return T_FS_REPORT_LSN; } YY_BREAK case 91: YY_RULE_SETUP -#line 243 "test_spec_scan.l" -{ return T_FS_FAST_FORWARD; } +#line 243 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_REPORT_LSN; } YY_BREAK case 92: YY_RULE_SETUP -#line 244 "test_spec_scan.l" +#line 244 "src/bin/pgaftest/test_spec_scan.l" { return T_FS_FAST_FORWARD; } YY_BREAK case 93: YY_RULE_SETUP -#line 245 "test_spec_scan.l" -{ return T_FS_JOIN_SECONDARY; } +#line 245 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_FAST_FORWARD; } YY_BREAK case 94: YY_RULE_SETUP -#line 246 "test_spec_scan.l" +#line 246 "src/bin/pgaftest/test_spec_scan.l" { return T_FS_JOIN_SECONDARY; } YY_BREAK case 95: YY_RULE_SETUP -#line 247 "test_spec_scan.l" -{ return T_FS_DROPPED; } +#line 247 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_JOIN_SECONDARY; } YY_BREAK case 96: YY_RULE_SETUP -#line 249 "test_spec_scan.l" +#line 248 "src/bin/pgaftest/test_spec_scan.l" +{ return T_FS_DROPPED; } + YY_BREAK +case 97: +YY_RULE_SETUP +#line 250 "src/bin/pgaftest/test_spec_scan.l" { yylval.str = pgaf_strdup(yytext); return T_IDENT; } YY_BREAK -case 97: +case 98: YY_RULE_SETUP -#line 254 "test_spec_scan.l" +#line 255 "src/bin/pgaftest/test_spec_scan.l" { /* comment */ } YY_BREAK -case 98: -/* rule 98 can match eol */ +case 99: +/* rule 99 can match eol */ YY_RULE_SETUP -#line 255 "test_spec_scan.l" +#line 256 "src/bin/pgaftest/test_spec_scan.l" { pgaf_line_number++; } YY_BREAK -case 99: +case 100: YY_RULE_SETUP -#line 256 "test_spec_scan.l" +#line 257 "src/bin/pgaftest/test_spec_scan.l" { /* whitespace */ } YY_BREAK -case 100: +case 101: YY_RULE_SETUP -#line 258 "test_spec_scan.l" +#line 259 "src/bin/pgaftest/test_spec_scan.l" { BEGIN(EXEC_ARGS); return T_EXEC_FAILS; } YY_BREAK -case 101: +case 102: YY_RULE_SETUP -#line 259 "test_spec_scan.l" +#line 260 "src/bin/pgaftest/test_spec_scan.l" { BEGIN(EXEC_ARGS); return T_EXEC; } YY_BREAK -case 102: +case 103: YY_RULE_SETUP -#line 260 "test_spec_scan.l" +#line 261 "src/bin/pgaftest/test_spec_scan.l" { BEGIN(EXEC_ARGS); return T_RUN; } YY_BREAK -case 103: +case 104: YY_RULE_SETUP -#line 261 "test_spec_scan.l" +#line 262 "src/bin/pgaftest/test_spec_scan.l" { BEGIN(EXEC_ARGS); return T_PG_AUTOCTL; } YY_BREAK -case 104: +case 105: YY_RULE_SETUP -#line 263 "test_spec_scan.l" +#line 264 "src/bin/pgaftest/test_spec_scan.l" { return T_WAIT; } YY_BREAK -case 105: +case 106: YY_RULE_SETUP -#line 264 "test_spec_scan.l" +#line 265 "src/bin/pgaftest/test_spec_scan.l" { return T_UNTIL; } YY_BREAK -case 106: +case 107: YY_RULE_SETUP -#line 265 "test_spec_scan.l" +#line 266 "src/bin/pgaftest/test_spec_scan.l" { return T_TIMEOUT; } YY_BREAK -case 107: +case 108: YY_RULE_SETUP -#line 266 "test_spec_scan.l" +#line 267 "src/bin/pgaftest/test_spec_scan.l" { return T_ASSERT; } YY_BREAK -case 108: +case 109: YY_RULE_SETUP -#line 267 "test_spec_scan.l" +#line 268 "src/bin/pgaftest/test_spec_scan.l" { return T_SQL; } YY_BREAK -case 109: +case 110: YY_RULE_SETUP -#line 268 "test_spec_scan.l" +#line 269 "src/bin/pgaftest/test_spec_scan.l" { return T_EXPECT; } YY_BREAK -case 110: +case 111: YY_RULE_SETUP -#line 269 "test_spec_scan.l" +#line 270 "src/bin/pgaftest/test_spec_scan.l" { return T_ERROR; } YY_BREAK -case 111: +case 112: YY_RULE_SETUP -#line 270 "test_spec_scan.l" +#line 271 "src/bin/pgaftest/test_spec_scan.l" { return T_PROMOTE; } YY_BREAK -case 112: +case 113: YY_RULE_SETUP -#line 271 "test_spec_scan.l" +#line 272 "src/bin/pgaftest/test_spec_scan.l" { return T_NETWORK; } YY_BREAK -case 113: +case 114: YY_RULE_SETUP -#line 272 "test_spec_scan.l" +#line 273 "src/bin/pgaftest/test_spec_scan.l" { return T_DISCONNECT; } YY_BREAK -case 114: +case 115: YY_RULE_SETUP -#line 273 "test_spec_scan.l" +#line 274 "src/bin/pgaftest/test_spec_scan.l" { return T_CONNECT; } YY_BREAK -case 115: +case 116: YY_RULE_SETUP -#line 274 "test_spec_scan.l" +#line 275 "src/bin/pgaftest/test_spec_scan.l" { return T_SLEEP; } YY_BREAK -case 116: +case 117: YY_RULE_SETUP -#line 275 "test_spec_scan.l" +#line 276 "src/bin/pgaftest/test_spec_scan.l" { return T_COMPOSE; } YY_BREAK -case 117: +case 118: YY_RULE_SETUP -#line 276 "test_spec_scan.l" +#line 277 "src/bin/pgaftest/test_spec_scan.l" { return T_DOWN; } YY_BREAK -case 118: +case 119: YY_RULE_SETUP -#line 277 "test_spec_scan.l" +#line 278 "src/bin/pgaftest/test_spec_scan.l" { return T_START; } YY_BREAK -case 119: +case 120: YY_RULE_SETUP -#line 278 "test_spec_scan.l" +#line 279 "src/bin/pgaftest/test_spec_scan.l" { return T_STOP; } YY_BREAK -case 120: +case 121: YY_RULE_SETUP -#line 279 "test_spec_scan.l" +#line 280 "src/bin/pgaftest/test_spec_scan.l" { return T_STOPPED; } YY_BREAK -case 121: +case 122: YY_RULE_SETUP -#line 280 "test_spec_scan.l" +#line 281 "src/bin/pgaftest/test_spec_scan.l" { return T_KILL; } YY_BREAK -case 122: +case 123: YY_RULE_SETUP -#line 281 "test_spec_scan.l" +#line 282 "src/bin/pgaftest/test_spec_scan.l" { return T_IN; } YY_BREAK -case 123: +case 124: YY_RULE_SETUP -#line 282 "test_spec_scan.l" +#line 283 "src/bin/pgaftest/test_spec_scan.l" { return T_STATE; } YY_BREAK -case 124: +case 125: YY_RULE_SETUP -#line 283 "test_spec_scan.l" +#line 284 "src/bin/pgaftest/test_spec_scan.l" { return T_ASSIGNED_STATE; } YY_BREAK -case 125: +case 126: YY_RULE_SETUP -#line 284 "test_spec_scan.l" +#line 285 "src/bin/pgaftest/test_spec_scan.l" { return T_CANDIDATE_PRIORITY; } YY_BREAK -case 126: +case 127: YY_RULE_SETUP -#line 285 "test_spec_scan.l" +#line 286 "src/bin/pgaftest/test_spec_scan.l" { return T_GROUP; } YY_BREAK -case 127: +case 128: YY_RULE_SETUP -#line 286 "test_spec_scan.l" +#line 287 "src/bin/pgaftest/test_spec_scan.l" { return T_AND; } YY_BREAK -case 128: +case 129: YY_RULE_SETUP -#line 287 "test_spec_scan.l" +#line 288 "src/bin/pgaftest/test_spec_scan.l" { return T_IS; } YY_BREAK -case 129: +case 130: YY_RULE_SETUP -#line 288 "test_spec_scan.l" +#line 289 "src/bin/pgaftest/test_spec_scan.l" { return T_WITH; } YY_BREAK -case 130: +case 131: YY_RULE_SETUP -#line 289 "test_spec_scan.l" +#line 290 "src/bin/pgaftest/test_spec_scan.l" { return T_EQUALS; } YY_BREAK -case 131: +case 132: YY_RULE_SETUP -#line 290 "test_spec_scan.l" +#line 291 "src/bin/pgaftest/test_spec_scan.l" { return T_COMMA; } YY_BREAK -case 132: +case 133: YY_RULE_SETUP -#line 291 "test_spec_scan.l" +#line 292 "src/bin/pgaftest/test_spec_scan.l" { return T_POSTGRES; } YY_BREAK -case 133: +case 134: YY_RULE_SETUP -#line 292 "test_spec_scan.l" +#line 293 "src/bin/pgaftest/test_spec_scan.l" { return T_STAYS; } YY_BREAK -case 134: +case 135: YY_RULE_SETUP -#line 293 "test_spec_scan.l" +#line 294 "src/bin/pgaftest/test_spec_scan.l" { return T_WHILE; } YY_BREAK -case 135: +case 136: YY_RULE_SETUP -#line 294 "test_spec_scan.l" +#line 295 "src/bin/pgaftest/test_spec_scan.l" { return T_THROUGH; } YY_BREAK -case 136: +case 137: YY_RULE_SETUP -#line 295 "test_spec_scan.l" +#line 296 "src/bin/pgaftest/test_spec_scan.l" { return T_SET; } YY_BREAK -case 137: +case 138: YY_RULE_SETUP -#line 296 "test_spec_scan.l" +#line 297 "src/bin/pgaftest/test_spec_scan.l" { BEGIN(EXEC_ARGS); return T_INJECT; } YY_BREAK -case 138: +case 139: YY_RULE_SETUP -#line 297 "test_spec_scan.l" +#line 298 "src/bin/pgaftest/test_spec_scan.l" { return T_LOGS; } YY_BREAK -case 139: +case 140: YY_RULE_SETUP -#line 298 "test_spec_scan.l" +#line 299 "src/bin/pgaftest/test_spec_scan.l" { return T_NOT; } YY_BREAK -case 140: +case 141: YY_RULE_SETUP -#line 299 "test_spec_scan.l" +#line 300 "src/bin/pgaftest/test_spec_scan.l" { return T_CONTAINS; } YY_BREAK -case 141: +case 142: YY_RULE_SETUP -#line 300 "test_spec_scan.l" +#line 301 "src/bin/pgaftest/test_spec_scan.l" { return T_MATCHES; } YY_BREAK -case 142: +case 143: YY_RULE_SETUP -#line 302 "test_spec_scan.l" +#line 303 "src/bin/pgaftest/test_spec_scan.l" { yylval.ival = atoi(yytext); return T_INTEGER; } YY_BREAK -case 143: -/* rule 143 can match eol */ +case 144: +/* rule 144 can match eol */ YY_RULE_SETUP -#line 307 "test_spec_scan.l" +#line 308 "src/bin/pgaftest/test_spec_scan.l" { yytext[yyleng - 1] = '\0'; yylval.str = pgaf_strdup(yytext + 1); return T_STRING; } YY_BREAK -case 144: +case 145: YY_RULE_SETUP -#line 313 "test_spec_scan.l" +#line 314 "src/bin/pgaftest/test_spec_scan.l" { if (pgaf_next_brace_is_while) { pgaf_next_brace_is_while = 0; @@ -2259,9 +2271,9 @@ YY_RULE_SETUP return T_BLOCK; } YY_BREAK -case 145: +case 146: YY_RULE_SETUP -#line 323 "test_spec_scan.l" +#line 324 "src/bin/pgaftest/test_spec_scan.l" { if (pgaf_step_brace_depth > 0) { pgaf_step_brace_depth--; @@ -2272,40 +2284,40 @@ YY_RULE_SETUP return T_RBRACE; } YY_BREAK -case 146: +case 147: YY_RULE_SETUP -#line 333 "test_spec_scan.l" +#line 334 "src/bin/pgaftest/test_spec_scan.l" { yylval.str = pgaf_strdup(yytext); return T_IDENT; } YY_BREAK -case 147: +case 148: YY_RULE_SETUP -#line 338 "test_spec_scan.l" +#line 339 "src/bin/pgaftest/test_spec_scan.l" { /* skip whitespace before service name */ } YY_BREAK -case 148: +case 149: YY_RULE_SETUP -#line 340 "test_spec_scan.l" +#line 341 "src/bin/pgaftest/test_spec_scan.l" { yylval.str = pgaf_strdup(yytext); BEGIN(EXEC_ARGS_REST); return T_IDENT; } YY_BREAK -case 149: -/* rule 149 can match eol */ +case 150: +/* rule 150 can match eol */ YY_RULE_SETUP -#line 346 "test_spec_scan.l" +#line 347 "src/bin/pgaftest/test_spec_scan.l" { pgaf_line_number++; BEGIN(STEP_BODY); } YY_BREAK -case 150: +case 151: YY_RULE_SETUP -#line 351 "test_spec_scan.l" +#line 352 "src/bin/pgaftest/test_spec_scan.l" { char *p = yytext; while (*p == ' ' || *p == '\t') p++; @@ -2314,21 +2326,21 @@ YY_RULE_SETUP return T_SHELL_ARGS; } YY_BREAK -case 151: -/* rule 151 can match eol */ +case 152: +/* rule 152 can match eol */ YY_RULE_SETUP -#line 359 "test_spec_scan.l" +#line 360 "src/bin/pgaftest/test_spec_scan.l" { pgaf_line_number++; BEGIN(STEP_BODY); } YY_BREAK -case 152: +case 153: YY_RULE_SETUP -#line 364 "test_spec_scan.l" +#line 365 "src/bin/pgaftest/test_spec_scan.l" ECHO; YY_BREAK -#line 2331 "test_spec_scan.c" +#line 2343 "src/bin/pgaftest/test_spec_scan.c" case YY_STATE_EOF(INITIAL): case YY_STATE_EOF(CLUSTER_BODY): case YY_STATE_EOF(STEP_BODY): @@ -2630,7 +2642,7 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 1178 ) + if ( yy_current_state >= 1182 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; @@ -2658,11 +2670,11 @@ static int yy_get_next_buffer (void) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 1178 ) + if ( yy_current_state >= 1182 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 1177); + yy_is_jam = (yy_current_state == 1181); return yy_is_jam ? 0 : yy_current_state; } @@ -3301,7 +3313,7 @@ void yyfree (void * ptr ) #define YYTABLES_NAME "yytables" -#line 364 "test_spec_scan.l" +#line 365 "src/bin/pgaftest/test_spec_scan.l" static void diff --git a/src/bin/pgaftest/test_spec_scan.l b/src/bin/pgaftest/test_spec_scan.l index 25eaa9e0d..20562a261 100644 --- a/src/bin/pgaftest/test_spec_scan.l +++ b/src/bin/pgaftest/test_spec_scan.l @@ -178,6 +178,7 @@ static void pgaf_read_raw_block(void); "listen" { return T_LISTEN; } "citus-secondary" { return T_CITUS_SECONDARY; } "candidate-priority" { return T_CANDIDATE_PRIORITY; } +"region" { return T_REGION; } "group" { return T_GROUP; } "port" { return T_PORT; } "citus-cluster-name" { return T_CITUS_CLUSTER_NAME; } diff --git a/src/monitor/Makefile b/src/monitor/Makefile index f74d3245d..a092841e6 100644 --- a/src/monitor/Makefile +++ b/src/monitor/Makefile @@ -2,7 +2,7 @@ # Licensed under the PostgreSQL License. EXTENSION = pgautofailover -EXTVERSION = 2.2 +EXTVERSION = 2.3 SRC_DIR := $(dir $(abspath $(lastword $(MAKEFILE_LIST)))) diff --git a/src/monitor/expected/dummy_update.out b/src/monitor/expected/dummy_update.out index 0c2df4d28..a8c05d9e2 100644 --- a/src/monitor/expected/dummy_update.out +++ b/src/monitor/expected/dummy_update.out @@ -19,5 +19,5 @@ select installed_version -- should error because installed extension isn't compatible with .so select * from pgautofailover.get_primary('unknown formation'); ERROR: loaded "pgautofailover" library version differs from installed extension version -DETAIL: Loaded library requires 2.2, but the installed extension version is dummy. +DETAIL: Loaded library requires 2.3, but the installed extension version is dummy. HINT: Run ALTER EXTENSION pgautofailover UPDATE and try again. diff --git a/src/monitor/expected/monitor.out b/src/monitor/expected/monitor.out index 2e8f6f5a8..6b937bf9f 100644 --- a/src/monitor/expected/monitor.out +++ b/src/monitor/expected/monitor.out @@ -97,7 +97,8 @@ assigned_replication_quorum | t assigned_node_name | node_3 select formationid, nodename, goalstate, reportedstate - from pgautofailover.node; + from pgautofailover.node + order by nodeid; -[ RECORD 1 ]-+------------- formationid | default nodename | node_1 diff --git a/src/monitor/expected/pg19/expected/monitor.out b/src/monitor/expected/pg19/expected/monitor.out index 22f3aafb8..1fa8dd8c0 100644 --- a/src/monitor/expected/pg19/expected/monitor.out +++ b/src/monitor/expected/pg19/expected/monitor.out @@ -97,7 +97,8 @@ assigned_replication_quorum | t assigned_node_name | node_3 select formationid, nodename, goalstate, reportedstate - from pgautofailover.node; + from pgautofailover.node + order by nodeid; -[ RECORD 1 ]-+------------- formationid | default nodename | node_1 diff --git a/src/monitor/expected/upgrade_1.out b/src/monitor/expected/upgrade_1.out index bc323db63..eac85691e 100644 --- a/src/monitor/expected/upgrade_1.out +++ b/src/monitor/expected/upgrade_1.out @@ -5,7 +5,7 @@ CREATE EXTENSION pgautofailover VERSION '1.0'; List of installed extensions Name | Version | Default version | Schema | Description ----------------+---------+-----------------+--------+------------------ - pgautofailover | 1.0 | 2.2 | public | pg_auto_failover + pgautofailover | 1.0 | 2.3 | public | pg_auto_failover (1 row) ALTER EXTENSION pgautofailover UPDATE TO '1.1'; @@ -13,7 +13,7 @@ ALTER EXTENSION pgautofailover UPDATE TO '1.1'; List of installed extensions Name | Version | Default version | Schema | Description ----------------+---------+-----------------+--------+------------------ - pgautofailover | 1.1 | 2.2 | public | pg_auto_failover + pgautofailover | 1.1 | 2.3 | public | pg_auto_failover (1 row) ALTER EXTENSION pgautofailover UPDATE TO '1.2'; @@ -21,7 +21,7 @@ ALTER EXTENSION pgautofailover UPDATE TO '1.2'; List of installed extensions Name | Version | Default version | Schema | Description ----------------+---------+-----------------+--------+------------------ - pgautofailover | 1.2 | 2.2 | public | pg_auto_failover + pgautofailover | 1.2 | 2.3 | public | pg_auto_failover (1 row) ALTER EXTENSION pgautofailover UPDATE TO '1.3'; @@ -29,7 +29,7 @@ ALTER EXTENSION pgautofailover UPDATE TO '1.3'; List of installed extensions Name | Version | Default version | Schema | Description ----------------+---------+-----------------+--------+------------------ - pgautofailover | 1.3 | 2.2 | public | pg_auto_failover + pgautofailover | 1.3 | 2.3 | public | pg_auto_failover (1 row) DROP EXTENSION pgautofailover; diff --git a/src/monitor/group_state_machine.c b/src/monitor/group_state_machine.c index e9cd94247..f84b55a12 100644 --- a/src/monitor/group_state_machine.c +++ b/src/monitor/group_state_machine.c @@ -81,6 +81,7 @@ static bool WalDifferenceWithin(AutoFailoverNode *secondaryNode, /* GUC variables */ int EnableSyncXlogThreshold = DEFAULT_XLOG_SEG_SIZE; int PromoteXlogThreshold = DEFAULT_XLOG_SEG_SIZE; +int ReplicationStallTimeoutMs = 10 * 1000; /* @@ -106,6 +107,7 @@ BuildGroupStateContext(GroupStateContext *ctx, AutoFailoverNode *activeNode) ctx->unhealthyTimeoutMs = UnhealthyTimeoutMs; ctx->drainTimeoutMs = DrainTimeoutMs; ctx->startupGracePeriodMs = StartupGracePeriodMs; + ctx->replicationStallTimeoutMs = ReplicationStallTimeoutMs; if (ctx->formation == NULL) { @@ -275,6 +277,40 @@ ProceedGroupStateFromContext(GroupStateContext *ctx) ReplicationStateGetName(activeNode->goalState)))); } + /* + * Replication stall detection (issue #997 — 3-DC split-brain). + * + * When the primary is healthy (monitor can reach it) but no standby has + * appeared in pg_stat_replication for longer than + * pgautofailover.replication_stall_timeout, we assign wait_primary. + * That clears synchronous_standby_names so COMMIT no longer hangs. + * + * replication_stall_since is set/cleared by ReportAutoFailoverNodeState() + * each time the keeper calls node_active(). + */ + if (IsInPrimaryState(primaryNode) && + NodeIsHealthy(primaryNode, ctx) && + primaryNode->replicationStallSince != 0 && + TimestampDifferenceExceeds(primaryNode->replicationStallSince, + ctx->now, + ctx->replicationStallTimeoutMs)) + { + char message[BUFSIZE] = { 0 }; + + LogAndNotifyMessage( + message, BUFSIZE, + "Setting goal state of " NODE_FORMAT + " to wait_primary: no standby has been connected in " + "pg_stat_replication for more than %dms " + "(pgautofailover.replication_stall_timeout).", + NODE_FORMAT_ARGS(primaryNode), + ctx->replicationStallTimeoutMs); + + AssignGoalState(primaryNode, REPLICATION_STATE_WAIT_PRIMARY, message); + + return true; + } + /* Multiple Standby failover is handled in its own function. */ if (nodesCount > 2 && NodeIsUnhealthy(primaryNode, ctx)) { diff --git a/src/monitor/group_state_machine.h b/src/monitor/group_state_machine.h index 65e9f0fac..17effdd17 100644 --- a/src/monitor/group_state_machine.h +++ b/src/monitor/group_state_machine.h @@ -58,6 +58,7 @@ typedef struct GroupStateContext int unhealthyTimeoutMs; int drainTimeoutMs; int startupGracePeriodMs; + int replicationStallTimeoutMs; } GroupStateContext; @@ -73,3 +74,4 @@ extern int PromoteXlogThreshold; extern int DrainTimeoutMs; extern int UnhealthyTimeoutMs; extern int StartupGracePeriodMs; +extern int ReplicationStallTimeoutMs; diff --git a/src/monitor/metadata.h b/src/monitor/metadata.h index f7325c86e..d974d8bff 100644 --- a/src/monitor/metadata.h +++ b/src/monitor/metadata.h @@ -15,7 +15,7 @@ #include "storage/lockdefs.h" -#define AUTO_FAILOVER_EXTENSION_VERSION "2.2" +#define AUTO_FAILOVER_EXTENSION_VERSION "2.3" #define AUTO_FAILOVER_EXTENSION_NAME "pgautofailover" #define AUTO_FAILOVER_SCHEMA_NAME "pgautofailover" #define AUTO_FAILOVER_FORMATION_TABLE "pgautofailover.formation" diff --git a/src/monitor/node_active_protocol.c b/src/monitor/node_active_protocol.c index f112e0501..a82c20c98 100644 --- a/src/monitor/node_active_protocol.c +++ b/src/monitor/node_active_protocol.c @@ -43,6 +43,7 @@ static AutoFailoverNodeState * NodeActive(char *formationId, static void JoinAutoFailoverFormation(AutoFailoverFormation *formation, char *nodeName, char *nodeHost, int nodePort, uint64 sysIdentifier, char *nodeCluster, + char *region, AutoFailoverNodeState *currentNodeState); static int AssignGroupId(AutoFailoverFormation *formation, char *nodeHost, int nodePort, @@ -111,6 +112,9 @@ register_node(PG_FUNCTION_ARGS) text *nodeClusterText = PG_GETARG_TEXT_P(12); char *nodeCluster = text_to_cstring(nodeClusterText); + text *nodeRegionText = PG_GETARG_TEXT_P(13); + char *nodeRegion = text_to_cstring(nodeRegionText); + AutoFailoverNodeState currentNodeState = { 0 }; currentNodeState.nodeId = currentNodeId; @@ -194,6 +198,7 @@ register_node(PG_FUNCTION_ARGS) nodePort, sysIdentifier, nodeCluster, + nodeRegion, ¤tNodeState); AutoFailoverNode *pgAutoFailoverNode = GetAutoFailoverNode(nodeHost, nodePort); @@ -529,6 +534,7 @@ static void JoinAutoFailoverFormation(AutoFailoverFormation *formation, char *nodeName, char *nodeHost, int nodePort, uint64 sysIdentifier, char *nodeCluster, + char *region, AutoFailoverNodeState *currentNodeState) { int groupId = -1; @@ -695,7 +701,8 @@ JoinAutoFailoverFormation(AutoFailoverFormation *formation, currentNodeState->replicationState, currentNodeState->candidatePriority, currentNodeState->replicationQuorum, - nodeCluster); + nodeCluster, + region); currentNodeState->groupId = groupId; } diff --git a/src/monitor/node_metadata.c b/src/monitor/node_metadata.c index 5fba2596e..b13a9688f 100644 --- a/src/monitor/node_metadata.c +++ b/src/monitor/node_metadata.c @@ -169,6 +169,15 @@ TupleToAutoFailoverNode(TupleDesc tupleDescriptor, HeapTuple heapTuple) Datum nodeCluster = heap_getattr(heapTuple, Anum_pgautofailover_node_nodecluster, tupleDescriptor, &isNull); + bool regionIsNull = false; + Datum region = heap_getattr(heapTuple, + Anum_pgautofailover_node_region, + tupleDescriptor, ®ionIsNull); + bool stallIsNull = false; + Datum replicationStallSince = + heap_getattr(heapTuple, + Anum_pgautofailover_node_replication_stall_since, + tupleDescriptor, &stallIsNull); Oid goalStateOid = DatumGetObjectId(goalState); Oid reportedStateOid = DatumGetObjectId(reportedState); @@ -200,6 +209,10 @@ TupleToAutoFailoverNode(TupleDesc tupleDescriptor, HeapTuple heapTuple) pgAutoFailoverNode->candidatePriority = DatumGetInt32(candidatePriority); pgAutoFailoverNode->replicationQuorum = DatumGetBool(replicationQuorum); pgAutoFailoverNode->nodeCluster = TextDatumGetCString(nodeCluster); + pgAutoFailoverNode->region = + regionIsNull ? "" : TextDatumGetCString(region); + pgAutoFailoverNode->replicationStallSince = + stallIsNull ? 0 : DatumGetTimestampTz(replicationStallSince); return pgAutoFailoverNode; } @@ -1112,7 +1125,8 @@ AddAutoFailoverNode(char *formationId, ReplicationState reportedState, int candidatePriority, bool replicationQuorum, - char *nodeCluster) + char *nodeCluster, + char *region) { Oid goalStateOid = ReplicationStateGetEnum(goalState); Oid reportedStateOid = ReplicationStateGetEnum(reportedState); @@ -1136,7 +1150,8 @@ AddAutoFailoverNode(char *formationId, INT4OID, /* candidate_priority */ BOOLOID, /* replication_quorum */ TEXTOID, /* node name prefix */ - TEXTOID /* nodecluster */ + TEXTOID, /* nodecluster */ + TEXTOID /* region */ }; Datum argValues[] = { @@ -1152,7 +1167,8 @@ AddAutoFailoverNode(char *formationId, Int32GetDatum(candidatePriority), /* candidate_priority */ BoolGetDatum(replicationQuorum), /* replication_quorum */ CStringGetTextDatum(prefix), /* prefix */ - CStringGetTextDatum(nodeCluster) /* nodecluster */ + CStringGetTextDatum(nodeCluster), /* nodecluster */ + CStringGetTextDatum(region) /* region */ }; /* @@ -1178,7 +1194,8 @@ AddAutoFailoverNode(char *formationId, ' ', /* candidate_priority */ ' ', /* replication_quorum */ ' ', /* prefix */ - ' ' /* nodecluster */ + ' ', /* nodecluster */ + ' ' /* region */ }; const int argCount = sizeof(argValues) / sizeof(argValues[0]); @@ -1208,7 +1225,7 @@ AddAutoFailoverNode(char *formationId, "INSERT INTO " AUTO_FAILOVER_NODE_TABLE " (formationid, nodeid, groupid, nodename, nodehost, nodeport, " " sysidentifier, goalstate, reportedstate, " - " candidatepriority, replicationquorum, nodecluster)" + " candidatepriority, replicationquorum, nodecluster, region)" " SELECT $1, seq.nodeid, $3, " " case when $4 is null " " then case when $12 = 'node' " @@ -1222,7 +1239,7 @@ AddAutoFailoverNode(char *formationId, " end " " else $4 " " end, " - " $5, $6, $7, $8, $9, $10, $11, $13 " + " $5, $6, $7, $8, $9, $10, $11, $13, $14 " " FROM seq " "RETURNING nodeid"; @@ -1363,6 +1380,13 @@ ReportAutoFailoverNodeState(char *nodeHost, int nodePort, }; const int argCount = sizeof(argValues) / sizeof(argValues[0]); + /* + * Track when a PRIMARY node first loses its standby from + * pg_stat_replication. We set replication_stall_since on the first + * empty-sync-state report and clear it as soon as a standby reconnects. + * The FSM uses this timestamp to assign wait_primary after + * pgautofailover.replication_stall_timeout elapses (issue #997). + */ const char *updateQuery = "UPDATE " AUTO_FAILOVER_NODE_TABLE " SET reportedstate = $1, reporttime = now(), " @@ -1370,7 +1394,13 @@ ReportAutoFailoverNodeState(char *nodeHost, int nodePort, "reportedtli = CASE $4 WHEN 0 THEN reportedtli ELSE $4 END, " "reportedlsn = CASE $5 WHEN '0/0'::pg_lsn THEN reportedlsn ELSE $5 END, " "walreporttime = CASE $5 WHEN '0/0'::pg_lsn THEN walreporttime ELSE now() END, " - "statechangetime = CASE WHEN reportedstate <> $1 THEN now() ELSE statechangetime END " + "statechangetime = CASE WHEN reportedstate <> $1 THEN now() ELSE statechangetime END, " + "replication_stall_since = CASE " + " WHEN $1 = 'primary'::pgautofailover.replication_state" + " AND $3 = '' " + " THEN COALESCE(replication_stall_since, now()) " + " ELSE NULL " + "END " "WHERE nodehost = $6 AND nodeport = $7"; SPI_connect(); diff --git a/src/monitor/node_metadata.h b/src/monitor/node_metadata.h index 6c7440b6e..e77191aea 100644 --- a/src/monitor/node_metadata.h +++ b/src/monitor/node_metadata.h @@ -26,7 +26,7 @@ * indices must match with the columns given * in the following definition. */ -#define Natts_pgautofailover_node 19 +#define Natts_pgautofailover_node 21 #define Anum_pgautofailover_node_formationid 1 #define Anum_pgautofailover_node_nodeid 2 #define Anum_pgautofailover_node_groupid 3 @@ -48,6 +48,8 @@ #define Anum_pgautofailover_node_candidate_priority 19 #define Anum_pgautofailover_node_replication_quorum 20 #define Anum_pgautofailover_node_nodecluster 21 +#define Anum_pgautofailover_node_region 22 +#define Anum_pgautofailover_node_replication_stall_since 23 #define AUTO_FAILOVER_NODE_TABLE_ALL_COLUMNS \ "formationid, " \ @@ -70,7 +72,9 @@ "statechangetime, " \ "candidatepriority, " \ "replicationquorum, " \ - "nodecluster" + "nodecluster, " \ + "region, " \ + "replication_stall_since" #define SELECT_ALL_FROM_AUTO_FAILOVER_NODE_TABLE \ @@ -133,6 +137,8 @@ typedef struct AutoFailoverNode int candidatePriority; bool replicationQuorum; char *nodeCluster; + char *region; + TimestampTz replicationStallSince; /* 0 = not stalled */ } AutoFailoverNode; @@ -196,7 +202,8 @@ extern int AddAutoFailoverNode(char *formationId, ReplicationState reportedState, int candidatePriority, bool replicationQuorum, - char *nodeCluster); + char *nodeCluster, + char *region); extern void SetNodeGoalState(AutoFailoverNode *pgAutoFailoverNode, ReplicationState goalState, const char *message); diff --git a/src/monitor/pg_auto_failover.c b/src/monitor/pg_auto_failover.c index 40b7f1254..b94a4b92e 100644 --- a/src/monitor/pg_auto_failover.c +++ b/src/monitor/pg_auto_failover.c @@ -170,6 +170,15 @@ StartMonitorNode(void) NULL, &DrainTimeoutMs, 30 * 1000, 1, INT_MAX, PGC_SIGHUP, GUC_UNIT_MS, NULL, NULL, NULL); + DefineCustomIntVariable("pgautofailover.replication_stall_timeout", + "Assign wait_primary when the primary has had no standby " + "connected in pg_stat_replication for this long. " + "This unblocks writes in 3-DC topologies where the " + "primary-to-standby link fails while both nodes remain " + "reachable from the monitor.", + NULL, &ReplicationStallTimeoutMs, 10 * 1000, 1, INT_MAX, + PGC_SIGHUP, GUC_UNIT_MS, NULL, NULL, NULL); + DefineCustomIntVariable("pgautofailover.node_considered_unhealthy_timeout", "Mark node unhealthy if last ping was over this long ago", NULL, &UnhealthyTimeoutMs, 20 * 1000, 1, INT_MAX, diff --git a/src/monitor/pgautofailover--2.2--2.3.sql b/src/monitor/pgautofailover--2.2--2.3.sql new file mode 100644 index 000000000..16e77a460 --- /dev/null +++ b/src/monitor/pgautofailover--2.2--2.3.sql @@ -0,0 +1,150 @@ +-- Copyright (c) Microsoft Corporation. All rights reserved. +-- Licensed under the PostgreSQL License. + +-- complain if script is sourced in psql, rather than via ALTER EXTENSION +\echo Use "ALTER EXTENSION pgautofailover UPDATE TO '2.3'" to load this file. \quit + +-- +-- Add region and replication_stall_since columns to pgautofailover.node. +-- +-- region: operator-assigned label for the data-centre or availability zone +-- the node lives in. Used in watch output and future topology-aware routing. +-- +-- replication_stall_since: set by node_active() the first time a PRIMARY node +-- reports an empty pg_stat_replication (no standby connected). Cleared when +-- a standby reconnects. The FSM uses this to transition to wait_primary after +-- pgautofailover.replication_stall_timeout elapses, unblocking writes in +-- 3-DC topologies where the primary↔standby link breaks while both nodes +-- remain reachable from the monitor (issue #997). +-- + +ALTER TABLE pgautofailover.node + ADD COLUMN IF NOT EXISTS region text not null default 'default', + ADD COLUMN IF NOT EXISTS replication_stall_since timestamptz; + + +-- +-- Replace current_state() with a version that also returns the region column. +-- + +DROP FUNCTION IF EXISTS pgautofailover.current_state(text); +DROP FUNCTION IF EXISTS pgautofailover.current_state(text, int); + +CREATE FUNCTION pgautofailover.current_state + ( + IN formation_id text default 'default', + OUT formation_kind text, + OUT nodename text, + OUT nodehost text, + OUT nodeport int, + OUT group_id int, + OUT node_id bigint, + OUT current_group_state pgautofailover.replication_state, + OUT assigned_group_state pgautofailover.replication_state, + OUT candidate_priority int, + OUT replication_quorum bool, + OUT reported_tli int, + OUT reported_lsn pg_lsn, + OUT health integer, + OUT nodecluster text, + OUT noderegion text + ) +RETURNS SETOF record LANGUAGE SQL STRICT +AS $$ + select kind, nodename, nodehost, nodeport, groupid, nodeid, + reportedstate, goalstate, + candidatepriority, replicationquorum, + reportedtli, reportedlsn, health, nodecluster, region + from pgautofailover.node + join pgautofailover.formation using(formationid) + where formationid = formation_id + order by groupid, nodeid; +$$; + +comment on function pgautofailover.current_state(text) + is 'get the current state of both nodes of a formation'; + +grant execute on function pgautofailover.current_state(text) + to autoctl_node; + +CREATE FUNCTION pgautofailover.current_state + ( + IN formation_id text, + IN group_id int, + OUT formation_kind text, + OUT nodename text, + OUT nodehost text, + OUT nodeport int, + OUT group_id int, + OUT node_id bigint, + OUT current_group_state pgautofailover.replication_state, + OUT assigned_group_state pgautofailover.replication_state, + OUT candidate_priority int, + OUT replication_quorum bool, + OUT reported_tli int, + OUT reported_lsn pg_lsn, + OUT health integer, + OUT nodecluster text, + OUT noderegion text + ) +RETURNS SETOF record LANGUAGE SQL STRICT +AS $$ + select kind, nodename, nodehost, nodeport, groupid, nodeid, + reportedstate, goalstate, + candidatepriority, replicationquorum, + reportedtli, reportedlsn, health, nodecluster, region + from pgautofailover.node + join pgautofailover.formation using(formationid) + where formationid = formation_id + and groupid = group_id + order by groupid, nodeid; +$$; + +comment on function pgautofailover.current_state(text, int) + is 'get the current state of both nodes of a group in a formation'; + +grant execute on function pgautofailover.current_state(text, int) + to autoctl_node; + + +-- +-- Replace register_node() with a version that accepts the new node_region +-- parameter. The old 13-argument form is dropped first so the new 14-argument +-- form can be created cleanly. +-- + +DROP FUNCTION IF EXISTS pgautofailover.register_node( + text, text, int, name, text, bigint, bigint, int, + pgautofailover.replication_state, text, int, bool, text); + +CREATE FUNCTION pgautofailover.register_node + ( + IN formation_id text, + IN node_host text, + IN node_port int, + IN dbname name, + IN node_name text default '', + IN sysidentifier bigint default 0, + IN desired_node_id bigint default -1, + IN desired_group_id int default -1, + IN initial_group_role pgautofailover.replication_state default 'init', + IN node_kind text default 'standalone', + IN candidate_priority int default 100, + IN replication_quorum bool default true, + IN node_cluster text default 'default', + IN node_region text default 'default', + OUT assigned_node_id bigint, + OUT assigned_group_id int, + OUT assigned_group_state pgautofailover.replication_state, + OUT assigned_candidate_priority int, + OUT assigned_replication_quorum bool, + OUT assigned_node_name text + ) +RETURNS record LANGUAGE C STRICT SECURITY DEFINER +AS 'MODULE_PATHNAME', $$register_node$$; + +grant execute on function + pgautofailover.register_node(text,text,int,name,text,bigint,bigint,int, + pgautofailover.replication_state,text, + int,bool,text,text) + to autoctl_node; diff --git a/src/monitor/pgautofailover--2.3--dummy.sql b/src/monitor/pgautofailover--2.3--dummy.sql new file mode 100644 index 000000000..7167ee175 --- /dev/null +++ b/src/monitor/pgautofailover--2.3--dummy.sql @@ -0,0 +1,6 @@ +-- +-- dummy extension update file that does nothing +-- +-- complain if script is sourced in psql, rather than via CREATE EXTENSION +\echo Use "ALTER EXTENSION pgautofailover UPDATE TO dummy" to load this file. \quit + diff --git a/src/monitor/pgautofailover.control b/src/monitor/pgautofailover.control index 458378593..081bc691b 100644 --- a/src/monitor/pgautofailover.control +++ b/src/monitor/pgautofailover.control @@ -1,5 +1,5 @@ comment = 'pg_auto_failover' -default_version = '2.2' +default_version = '2.3' module_pathname = '$libdir/pgautofailover' relocatable = false requires = 'btree_gist' diff --git a/src/monitor/pgautofailover.sql b/src/monitor/pgautofailover.sql index fcf120725..af211561b 100644 --- a/src/monitor/pgautofailover.sql +++ b/src/monitor/pgautofailover.sql @@ -121,6 +121,8 @@ CREATE TABLE pgautofailover.node candidatepriority int not null default 100, replicationquorum bool not null default true, nodecluster text not null default 'default', + region text not null default 'default', + replication_stall_since timestamptz, -- node names must be unique in a given formation UNIQUE (formationid, nodename), @@ -256,6 +258,7 @@ CREATE FUNCTION pgautofailover.register_node IN candidate_priority int default 100, IN replication_quorum bool default true, IN node_cluster text default 'default', + IN node_region text default 'default', OUT assigned_node_id bigint, OUT assigned_group_id int, OUT assigned_group_state pgautofailover.replication_state, @@ -269,7 +272,7 @@ AS 'MODULE_PATHNAME', $$register_node$$; grant execute on function pgautofailover.register_node(text,text,int,name,text,bigint,bigint,int, pgautofailover.replication_state,text, - int,bool,text) + int,bool,text,text) to autoctl_node; @@ -603,14 +606,15 @@ CREATE FUNCTION pgautofailover.current_state OUT reported_tli int, OUT reported_lsn pg_lsn, OUT health integer, - OUT nodecluster text + OUT nodecluster text, + OUT noderegion text ) RETURNS SETOF record LANGUAGE SQL STRICT AS $$ select kind, nodename, nodehost, nodeport, groupid, nodeid, reportedstate, goalstate, candidatepriority, replicationquorum, - reportedtli, reportedlsn, health, nodecluster + reportedtli, reportedlsn, health, nodecluster, region from pgautofailover.node join pgautofailover.formation using(formationid) where formationid = formation_id @@ -640,14 +644,15 @@ CREATE FUNCTION pgautofailover.current_state OUT reported_tli int, OUT reported_lsn pg_lsn, OUT health integer, - OUT nodecluster text + OUT nodecluster text, + OUT noderegion text ) RETURNS SETOF record LANGUAGE SQL STRICT AS $$ select kind, nodename, nodehost, nodeport, groupid, nodeid, reportedstate, goalstate, candidatepriority, replicationquorum, - reportedtli, reportedlsn, health, nodecluster + reportedtli, reportedlsn, health, nodecluster, region from pgautofailover.node join pgautofailover.formation using(formationid) where formationid = formation_id diff --git a/src/monitor/sql/monitor.sql b/src/monitor/sql/monitor.sql index 3f80e5537..b8c0a0685 100644 --- a/src/monitor/sql/monitor.sql +++ b/src/monitor/sql/monitor.sql @@ -43,7 +43,8 @@ select * from pgautofailover.register_node('default', 'localhost', 9879, 'postgres'); select formationid, nodename, goalstate, reportedstate - from pgautofailover.node; + from pgautofailover.node + order by nodeid; table pgautofailover.formation; diff --git a/tests/tap/schedule b/tests/tap/schedule index 8aad33a35..8f612fb1a 100644 --- a/tests/tap/schedule +++ b/tests/tap/schedule @@ -23,6 +23,7 @@ multi_ifdown multi_maintenance multi_alternate guard_data_loss +replication_stall_3dc fast_forward extension_update installcheck diff --git a/tests/tap/specs/replication_stall_3dc.pgaf b/tests/tap/specs/replication_stall_3dc.pgaf new file mode 100644 index 000000000..9aad0abd7 --- /dev/null +++ b/tests/tap/specs/replication_stall_3dc.pgaf @@ -0,0 +1,142 @@ +# Replication stall detection in a 3-DC topology. +# +# Background (issue #997): +# +# When the primary (dc1) and standby (dc2) lose connectivity while both +# remain reachable from the monitor (dc3), synchronous_standby_names stays +# set on the primary, causing every COMMIT to hang indefinitely. +# +# Fix: the monitor tracks replication_stall_since on the primary node row. +# As soon as the primary reports an empty pg_stat_replication sync_state +# (SYNC_STATE_UNKNOWN) for longer than +# pgautofailover.replication_stall_timeout (default 10 s), the FSM assigns +# wait_primary, which clears synchronous_standby_names and unblocks writes. +# +# Topology modelled here: +# +# dc1: primary (node1) — group 0 +# dc2: standby (node2) — group 0 +# dc3: monitor (compose host / pgaf-monitor service) +# +# The monitor is always reachable from both nodes (same Docker network), but +# we can sever the dc1↔dc2 link with `docker network disconnect`. +# This replicates the 3-DC split-brain scenario without requiring three +# separate Docker networks. +# +# Predecessor: none (new regression test for issue #997) + +cluster { + monitor + ssl off + formation { + node1 region dc1 + node2 region dc2 candidate-priority 50 + } +} + +setup { + # Wait for the initial topology to be healthy before starting steps + wait until node1 state = primary timeout 120s + wait until node2 state = secondary timeout 120s + + # Pre-create the smoke table used in write-check steps + sql node1 { + CREATE TABLE smoke (id serial PRIMARY KEY, v int); + INSERT INTO smoke (v) VALUES (0); + } + sql node2 { SELECT count(*) FROM smoke; } + expect { 1 } +} + +teardown { + # Restore node2 network access even if the test failed + network connect node2 + compose down +} + +# +# step 1: confirm synchronous_standby_names is active on the primary. +# + +step test_001_verify_sync_replication { + sql node1 { SHOW synchronous_standby_names; } + # value matches "ANY 1 (pgautofailover_standby_)" + expect { ANY 1 } + + # Write succeeds: the standby is connected and acknowledges immediately + sql node1 { INSERT INTO smoke (v) VALUES (1); } + sql node2 { SELECT max(v) FROM smoke; } + expect { 1 } +} + +# +# step 2: cut the dc1↔dc2 replication link. +# +# Both nodes remain able to reach the monitor; only the direct peer link +# between node1 and node2 is severed. +# + +step test_002_cut_replication_link { + # Disconnect node2 from the Docker network: the primary (node1) loses + # its standby connection while still reaching the monitor itself. + network disconnect node2 +} + +# +# step 3: the monitor must assign wait_primary within +# replication_stall_timeout (10 s default) + one keeper loop (5 s default). +# Allow up to 60 s total. +# + +step test_003_primary_becomes_wait_primary { + wait until node1 state = wait_primary timeout 60s + assert node1 state = wait_primary +} + +# +# step 4: verify that writes no longer hang. +# +# In wait_primary synchronous_standby_names is cleared, so COMMIT returns +# without waiting for the (now-unreachable) standby. +# + +step test_004_writes_unblock { + sql node1 { SHOW synchronous_standby_names; } + expect { } + + sql node1 { INSERT INTO smoke (v) VALUES (2); } + sql node1 { SELECT max(v) FROM smoke; } + expect { 2 } +} + +# +# step 5: restore the dc1↔dc2 link and let the standby re-join. +# + +step test_005_restore_link { + network connect node2 + + wait until node2 state = secondary timeout 120s + wait until node1 state = primary timeout 120s +} + +# +# step 6: confirm the cluster is healthy again and replication is in sync. +# + +step test_006_replication_restored { + sql node1 { SHOW synchronous_standby_names; } + expect { ANY 1 } + + # Row written during the stall must have replicated + sql node2 { SELECT max(v) FROM smoke; } + expect { 2 } +} + +sequence + test_001_verify_sync_replication + test_002_cut_replication_link + test_003_primary_becomes_wait_primary + test_004_writes_unblock + test_005_restore_link + test_006_replication_restored