From 5f53b42cfd053a724fcbe0712a9d5716e576a3e6 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Tue, 3 Jan 2023 17:56:37 -0500 Subject: [PATCH] During pg_dump startup, acquire table locks in batches. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 | 36 +++++++++++++++++++++++++++++++----- 1 file changed, 31 insertions(+), 5 deletions(-) diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c index 755d75ae4d..30718dd758 100644 --- a/src/bin/pg_dump/pg_dump.c +++ b/src/bin/pg_dump/pg_dump.c @@ -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");