aboutsummaryrefslogtreecommitdiff
path: root/src/bin/pg_basebackup/pg_recvlogical.c
diff options
context:
space:
mode:
authorNoah Misch <noah@leadboat.com>2020-05-13 20:42:09 -0700
committerNoah Misch <noah@leadboat.com>2020-05-13 20:42:23 -0700
commit7130be8aa3e022b08245f77cbbe5a71473b36a73 (patch)
tree50ac3da0927906c0eb7d4ebf151d34188affada7 /src/bin/pg_basebackup/pg_recvlogical.c
parent5060275aa8a1ead56e0a41308d7a43049a6cbe43 (diff)
downloadpostgresql-7130be8aa3e022b08245f77cbbe5a71473b36a73.tar.gz
postgresql-7130be8aa3e022b08245f77cbbe5a71473b36a73.zip
In successful pg_recvlogical, end PGRES_COPY_OUT cleanly.
pg_recvlogical merely called PQfinish(), so the backend sent messages after the disconnect. When that caused EPIPE in internal_flush(), before a LogicalConfirmReceivedLocation(), the next pg_recvlogical would repeat already-acknowledged records. Whether or not the defect causes EPIPE, post-disconnect messages could contain an ErrorResponse that the user should see. One properly ends PGRES_COPY_OUT by repeating PQgetCopyData() until it returns a negative value. Augment one of the tests to cover the case of WAL past --endpos. Back-patch to v10, where commit 7c030783a5bd07cadffc2a1018bc33119a4c7505 first appeared. Before that commit, pg_recvlogical never reached PGRES_COPY_OUT. Reported by Thomas Munro. Discussion: https://postgr.es/m/CAEepm=1MzM2Z_xNe4foGwZ1a+MO_2S9oYDq3M5D11=JDU_+0Nw@mail.gmail.com
Diffstat (limited to 'src/bin/pg_basebackup/pg_recvlogical.c')
-rw-r--r--src/bin/pg_basebackup/pg_recvlogical.c34
1 files changed, 30 insertions, 4 deletions
diff --git a/src/bin/pg_basebackup/pg_recvlogical.c b/src/bin/pg_basebackup/pg_recvlogical.c
index 90a3f41bbbe..679b901964b 100644
--- a/src/bin/pg_basebackup/pg_recvlogical.c
+++ b/src/bin/pg_basebackup/pg_recvlogical.c
@@ -582,14 +582,40 @@ StreamLogicalLog(void)
res = PQgetResult(conn);
if (PQresultStatus(res) == PGRES_COPY_OUT)
{
+ PQclear(res);
+
/*
* We're doing a client-initiated clean exit and have sent CopyDone to
- * the server. We've already sent replay confirmation and fsync'd so
- * we can just clean up the connection now.
+ * the server. Drain any messages, so we don't miss a last-minute
+ * ErrorResponse. The walsender stops generating XLogData records once
+ * it sees CopyDone, so expect this to finish quickly. After CopyDone,
+ * it's too late for sendFeedback(), even if this were to take a long
+ * time. Hence, use synchronous-mode PQgetCopyData().
*/
- goto error;
+ while (1)
+ {
+ int r;
+
+ if (copybuf != NULL)
+ {
+ PQfreemem(copybuf);
+ copybuf = NULL;
+ }
+ r = PQgetCopyData(conn, &copybuf, 0);
+ if (r == -1)
+ break;
+ if (r == -2)
+ {
+ pg_log_error("could not read COPY data: %s",
+ PQerrorMessage(conn));
+ time_to_abort = false; /* unclean exit */
+ goto error;
+ }
+ }
+
+ res = PQgetResult(conn);
}
- else if (PQresultStatus(res) != PGRES_COMMAND_OK)
+ if (PQresultStatus(res) != PGRES_COMMAND_OK)
{
pg_log_error("unexpected termination of replication stream: %s",
PQresultErrorMessage(res));