During pg_dump startup, acquire table locks in batches.
authorTom Lane <[email protected]>
Tue, 3 Jan 2023 22:56:37 +0000 (17:56 -0500)
committerTom Lane <[email protected]>
Tue, 3 Jan 2023 22:56:44 +0000 (17:56 -0500)
Combine multiple LOCK TABLE commands to reduce the number of
round trips to the server.  This is particularly helpful when
dumping from a remote server, but it seems useful even without
that.  In particular, shortening the time from seeing a table
in pg_class to acquiring lock on it reduces the window for
trouble from concurrent DDL.

Aleksander Alekseev, reviewed by Fabrízio de Royes Mello,
Gilles Darold, and Andres Freund

Discussion: https://postgr.es/m/CAJ7c6TO4z1+OBa-R+fC8FnaUgbEWJUf2Kq=nRngTW5EXtKru2g@mail.gmail.com

src/bin/pg_dump/pg_dump.c

index 755d75ae4dc37437079b34e0ed270ba89c925b0e..30718dd7582c6a60aced071d123a0cde3d79022f 100644 (file)
@@ -6470,6 +6470,8 @@ getTables(Archive *fout, int *numTables)
                ExecuteSqlStatement(fout, query->data);
        }
 
+       resetPQExpBuffer(query);
+
        for (i = 0; i < ntups; i++)
        {
                tblinfo[i].dobj.objType = DO_TABLE;
@@ -6587,14 +6589,38 @@ getTables(Archive *fout, int *numTables)
                        (tblinfo[i].relkind == RELKIND_RELATION ||
                         tblinfo[i].relkind == RELKIND_PARTITIONED_TABLE))
                {
-                       resetPQExpBuffer(query);
-                       appendPQExpBuffer(query,
-                                                         "LOCK TABLE %s IN ACCESS SHARE MODE",
-                                                         fmtQualifiedDumpable(&tblinfo[i]));
-                       ExecuteSqlStatement(fout, query->data);
+                       /*
+                        * Tables are locked in batches.  When dumping from a remote
+                        * server this can save a significant amount of time by reducing
+                        * the number of round trips.
+                        */
+                       if (query->len == 0)
+                               appendPQExpBuffer(query, "LOCK TABLE %s",
+                                                                 fmtQualifiedDumpable(&tblinfo[i]));
+                       else
+                       {
+                               appendPQExpBuffer(query, ", %s",
+                                                                 fmtQualifiedDumpable(&tblinfo[i]));
+
+                               /* Arbitrarily end a batch when query length reaches 100K. */
+                               if (query->len >= 100000)
+                               {
+                                       /* Lock another batch of tables. */
+                                       appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
+                                       ExecuteSqlStatement(fout, query->data);
+                                       resetPQExpBuffer(query);
+                               }
+                       }
                }
        }
 
+       if (query->len != 0)
+       {
+               /* Lock the tables in the last batch. */
+               appendPQExpBufferStr(query, " IN ACCESS SHARE MODE");
+               ExecuteSqlStatement(fout, query->data);
+       }
+
        if (dopt->lockWaitTimeout)
        {
                ExecuteSqlStatement(fout, "SET statement_timeout = 0");