During pg_dump startup, acquire table locks in batches.
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 3 Jan 2023 22:56:37 +0000 (17:56 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
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");