During pg_dump startup, acquire table locks in batches.

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
This commit is contained in:
Tom Lane 2023-01-03 17:56:37 -05:00
parent b23837dde4
commit 5f53b42cfd
1 changed files with 31 additions and 5 deletions

View 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");