From e7b71279924d62e363682ad3d0f2e291d08b1bd5 Mon Sep 17 00:00:00 2001
From: Aleksander Alekseev <aleksander@timescale.com>
Date: Wed, 7 Dec 2022 17:13:25 +0300
Subject: [PATCH v1] pg_dump: lock tables in batches

Instead of locking one table after another:

LOCK TABLE foo IN ACCESS SHARE MODE;
LOCK TABLE bar IN ACCESS SHARE MODE;
...

do this in batches:

LOCK TABLE foo, bar, ... IN ACCESS SHARE MODE;

When dumping multiple tables from a remote server this can save the user
a significant amount of time by reducing the amount of round trips.

In order to keep the length of the query reasonable the query is sent when
its length exceeds the given threshold which was arbitrary chosen as 1 MB.

Author: Aleksander Alekseev
Reported-by: David Kohn
Reviewed-by: TODO FIXME
Discussion: TODO FIXME
---
 src/bin/pg_dump/pg_dump.c | 41 ++++++++++++++++++++++++++++++++++-----
 1 file changed, 36 insertions(+), 5 deletions(-)

diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
index ad6693c358..be486686e9 100644
--- a/src/bin/pg_dump/pg_dump.c
+++ b/src/bin/pg_dump/pg_dump.c
@@ -154,6 +154,12 @@ static int	nseclabels = 0;
  */
 #define DUMP_DEFAULT_ROWS_PER_INSERT 1
 
+/*
+ * Send 'LOCK TABLE foo, bar, baz ...' when the length of the query exceeds
+ * the given threshold.
+ */
+#define LOCK_QUERY_THRESHOLD (1024*1024)
+
 /*
  * Macro for producing quoted, schema-qualified name of a dumpable object.
  */
@@ -6453,6 +6459,8 @@ getTables(Archive *fout, int *numTables)
 		ExecuteSqlStatement(fout, query->data);
 	}
 
+	resetPQExpBuffer(query);
+
 	for (i = 0; i < ntups; i++)
 	{
 		tblinfo[i].dobj.objType = DO_TABLE;
@@ -6570,14 +6578,37 @@ 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 multiple tables from
+			 * a remote server this can save the user a significant amount of
+			 * time by reducing the amount of round trips.
+			 */
+			if (query->len == 0)
+				appendPQExpBuffer(query, "LOCK TABLE %s",
+								  fmtQualifiedDumpable(&tblinfo[i]));
+			else
+			{
+				appendPQExpBuffer(query, ",%s",
+								  fmtQualifiedDumpable(&tblinfo[i]));
+
+				if (query->len >= LOCK_QUERY_THRESHOLD)
+				{
+					/* Lock another batch of tables. */
+					appendPQExpBuffer(query, " IN ACCESS SHARE MODE");
+					ExecuteSqlStatement(fout, query->data);
+					resetPQExpBuffer(query);
+				}
+			}
 		}
 	}
 
+	if (query->len != 0)
+	{
+		/* Lock the tables in the last batch. */
+		appendPQExpBuffer(query, " IN ACCESS SHARE MODE");
+		ExecuteSqlStatement(fout, query->data);
+	}
+
 	if (dopt->lockWaitTimeout)
 	{
 		ExecuteSqlStatement(fout, "SET statement_timeout = 0");
-- 
2.38.1

