Allow pg_dump to use jobs and serializable transactions together.
authorKevin Grittner <[email protected]>
Fri, 30 Jan 2015 14:57:24 +0000 (08:57 -0600)
committerKevin Grittner <[email protected]>
Fri, 30 Jan 2015 14:57:24 +0000 (08:57 -0600)
Since 9.3, when the --jobs option was introduced, using it together
with the --serializable-deferrable option generated multiple
errors.  We can get correct behavior by allowing the connection
which acquires the snapshot to use SERIALIZABLE, READ ONLY,
DEFERRABLE and pass that to the workers running the other
connections using REPEATABLE READ, READ ONLY.  This is a bit of a
kluge since the SERIALIZABLE behavior is achieved by running some
of the participating connections at a different isolation level,
but it is a simple and safe change, suitable for back-patching.

This will be followed by a proposal for a more invasive fix with
some slight behavioral changes on just the master branch, based on
suggestions from Andres Freund, but the kluge will be applied to
master until something is agreed along those lines.

Back-patched to 9.3, where the --jobs option was added.

Based on report from Alexander Korotkov

src/bin/pg_dump/pg_dump.c

index c3ebb3a9b0b55868a7303c85f9c262565d75affb..abebdacfdc9505d53b8982eade9fa6297766d420 100644 (file)
@@ -1011,7 +1011,15 @@ setup_connection(Archive *AH, DumpOptions *dopt, const char *dumpencoding,
    ExecuteSqlStatement(AH, "BEGIN");
    if (AH->remoteVersion >= 90100)
    {
-       if (dopt->serializable_deferrable)
+       /*
+        * To support the combination of serializable_deferrable with the jobs
+        * option we use REPEATABLE READ for the worker connections that are
+        * passed a snapshot.  As long as the snapshot is acquired in a
+        * SERIALIZABLE, READ ONLY, DEFERRABLE transaction, its use within a
+        * REPEATABLE READ transaction provides the appropriate integrity
+        * guarantees.  This is a kluge, but safe for back-patching.
+        */
+       if (dopt->serializable_deferrable && AH->sync_snapshot_id == NULL)
            ExecuteSqlStatement(AH,
                                "SET TRANSACTION ISOLATION LEVEL "
                                "SERIALIZABLE, READ ONLY, DEFERRABLE");