summaryrefslogtreecommitdiffstats
path: root/src/test/isolation/README
diff options
context:
space:
mode:
Diffstat (limited to 'src/test/isolation/README')
-rw-r--r--src/test/isolation/README214
1 files changed, 214 insertions, 0 deletions
diff --git a/src/test/isolation/README b/src/test/isolation/README
new file mode 100644
index 0000000..8457a56
--- /dev/null
+++ b/src/test/isolation/README
@@ -0,0 +1,214 @@
+src/test/isolation/README
+
+Isolation tests
+===============
+
+This directory contains a set of tests for concurrent behaviors in
+PostgreSQL. These tests require running multiple interacting transactions,
+which requires management of multiple concurrent connections, and therefore
+can't be tested using the normal pg_regress program. The name "isolation"
+comes from the fact that the original motivation was to test the
+serializable isolation level; but tests for other sorts of concurrent
+behaviors have been added as well.
+
+You can run the tests against the current build tree by typing
+ make check
+Alternatively, you can run against an existing installation by typing
+ make installcheck
+(This will contact a server at the default port expected by libpq.
+You can set PGPORT and so forth in your environment to control this.)
+
+To run just specific test(s) against an installed server,
+you can do something like
+ ./pg_isolation_regress fk-contention fk-deadlock
+(look into the specs/ subdirectory to see the available tests).
+
+Certain tests require the server's max_prepared_transactions parameter to be
+set to at least 3; therefore they are not run by default. To include them in
+the test run, use
+ make check-prepared-txns
+or
+ make installcheck-prepared-txns
+after making sure the server configuration is correct (see TEMP_CONFIG
+to adjust this in the "check" case).
+
+To define tests with overlapping transactions, we use test specification
+files with a custom syntax, which is described in the next section. To add
+a new test, place a spec file in the specs/ subdirectory, add the expected
+output in the expected/ subdirectory, and add the test's name to the
+isolation_schedule file.
+
+isolationtester is a program that uses libpq to open multiple connections,
+and executes a test specified by a spec file. A libpq connection string
+specifies the server and database to connect to; defaults derived from
+environment variables are used otherwise.
+
+pg_isolation_regress is a tool similar to pg_regress, but instead of using
+psql to execute a test, it uses isolationtester. It accepts all the same
+command-line arguments as pg_regress.
+
+By default, isolationtester will wait at most 300 seconds (5 minutes)
+for any one test step to complete. If you need to adjust this, set
+the environment variable PGISOLATIONTIMEOUT to the desired timeout
+in seconds.
+
+
+Test specification
+==================
+
+Each isolation test is defined by a specification file, stored in the specs
+subdirectory. A test specification defines some SQL "steps", groups them
+into "sessions" (where all the steps of one session will be run in the
+same backend), and specifies the "permutations" or orderings of the steps
+that are to be run.
+
+A test specification consists of four parts, in this order:
+
+setup { <SQL> }
+
+ The given SQL block is executed once (per permutation) before running
+ the test. Create any test tables or other required objects here. This
+ part is optional. Multiple setup blocks are allowed if needed; each is
+ run separately, in the given order. (The reason for allowing multiple
+ setup blocks is that each block is run as a single PQexec submission,
+ and some statements such as VACUUM cannot be combined with others in such
+ a block.)
+
+teardown { <SQL> }
+
+ The teardown SQL block is executed once after the test is finished. Use
+ this to clean up in preparation for the next permutation, e.g dropping
+ any test tables created by setup. This part is optional.
+
+session <name>
+
+ There are normally several "session" parts in a spec file. Each
+ session is executed in its own connection. A session part consists
+ of three parts: setup, teardown and one or more "steps". The per-session
+ setup and teardown parts have the same syntax as the per-test setup and
+ teardown described above, but they are executed in each session. The setup
+ part might, for example, contain a "BEGIN" command to begin a transaction.
+
+ Each step has the syntax
+
+ step <name> { <SQL> }
+
+ where <name> is a name identifying this step, and <SQL> is a SQL statement
+ (or statements, separated by semicolons) that is executed in the step.
+ Step names must be unique across the whole spec file.
+
+permutation <step name> ...
+
+ A permutation line specifies a list of steps that are run in that order.
+ Any number of permutation lines can appear. If no permutation lines are
+ given, the test program automatically runs all possible interleavings
+ of the steps from each session (running the steps of any one session in
+ order). Note that the list of steps in a manually specified
+ "permutation" line doesn't actually have to be a permutation of the
+ available steps; it could for instance repeat some steps more than once,
+ or leave others out. Also, each step name can be annotated with some
+ parenthesized markers, which are described below.
+
+Session and step names are SQL identifiers, either plain or double-quoted.
+A difference from standard SQL is that no case-folding occurs, so that
+FOO and "FOO" are the same name while FOO and Foo are different,
+whether you quote them or not. You must use quotes if you want to use
+an isolation test keyword (such as "permutation") as a name.
+
+A # character begins a comment, which extends to the end of the line.
+(This does not work inside <SQL> blocks, however. Use the usual SQL
+comment conventions there.)
+
+There is no way to include a "}" character in an <SQL> block.
+
+For each permutation of the session steps (whether these are manually
+specified in the spec file, or automatically generated), the isolation
+tester runs the main setup part, then per-session setup parts, then
+the selected session steps, then per-session teardown, then the main
+teardown script. Each selected step is sent to the connection associated
+with its session. The main setup and teardown scripts are run in a
+separate "control" session.
+
+
+Support for blocking commands
+=============================
+
+Each step may contain commands that block until further action has been taken
+(most likely, some other session runs a step that unblocks it or causes a
+deadlock). A test that uses this ability must manually specify valid
+permutations, i.e. those that would not expect a blocked session to execute a
+command. If a test fails to follow that rule, isolationtester will cancel it
+after PGISOLATIONTIMEOUT seconds. If the cancel doesn't work, isolationtester
+will exit uncleanly after a total of twice PGISOLATIONTIMEOUT. Testing
+invalid permutations should be avoided because they can make the isolation
+tests take a very long time to run, and they serve no useful testing purpose.
+
+Note that isolationtester recognizes that a command has blocked by looking
+to see if it is shown as waiting in the pg_locks view; therefore, only
+blocks on heavyweight locks will be detected.
+
+
+Dealing with race conditions
+============================
+
+In some cases, the isolationtester's output for a test script may vary
+due to timing issues. One way to deal with that is to create variant
+expected-files, which follow the usual PG convention that variants for
+foo.spec are named foo_1.out, foo_2.out, etc. However, this method is
+discouraged since the extra files are a nuisance for maintenance.
+Instead, it's usually possible to stabilize the test output by applying
+special markers to some of the step names listed in a permutation line.
+
+The general form of a permutation entry is
+
+ <step name> [ ( <marker> [ , <marker> ... ] ) ]
+
+where each marker defines a "blocking condition". The step will not be
+reported as completed before all the blocking conditions are satisfied.
+The possible markers are:
+
+ *
+ <other step name>
+ <other step name> notices <n>
+
+An asterisk marker, such as mystep(*), forces the isolationtester to
+report the step as "waiting" as soon as it's been launched, regardless of
+whether it would have been detected as waiting later. This is useful for
+stabilizing cases that are sometimes reported as waiting and other times
+reported as immediately completing, depending on the relative speeds of
+the step and the isolationtester's status-monitoring queries.
+
+A marker consisting solely of a step name indicates that this step may
+not be reported as completing until that other step has completed.
+This allows stabilizing cases where two queries might be seen to complete
+in either order. Note that this step can be *launched* before the other
+step has completed. (If the other step is used more than once in the
+current permutation, this step cannot complete while any of those
+instances is active.)
+
+A marker of the form "<other step name> notices <n>" (where <n> is a
+positive integer) indicates that this step may not be reported as
+completing until the other step's session has returned at least <n>
+NOTICE messages, counting from when this step is launched. This is useful
+for stabilizing cases where a step can return NOTICE messages before it
+actually completes, and those messages must be synchronized with the
+completions of other steps.
+
+Notice that these markers can only delay reporting of the completion
+of a step, not the launch of a step. The isolationtester will launch
+the next step in a permutation as soon as (A) all prior steps of the
+same session are done, and (B) the immediately preceding step in the
+permutation is done or deemed blocked. For this purpose, "deemed
+blocked" means that it has been seen to be waiting on a database lock,
+or that it is complete but the report of its completion is delayed by
+one of these markers.
+
+In some cases it is important not to launch a step until after the
+completion of a step in another session that could have been deemed
+blocked. An example is that if step s1 in session A is issuing a
+cancel for step s2 in session B, we'd better not launch B's next step
+till we're sure s1 is done. If s1 is blockable, trouble could ensue.
+The best way to prevent that is to create an empty step in session A
+and run it, without any markers, just before the next session B step.
+The empty step cannot be launched until s1 is done, and in turn the
+next session B step cannot be launched until the empty step finishes.