Skip to content

Commit 8222a9d

Browse files
committed
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 7c03078 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
1 parent 4fa8bd3 commit 8222a9d

File tree

2 files changed

+36
-5
lines changed

2 files changed

+36
-5
lines changed

src/bin/pg_basebackup/pg_recvlogical.c

Lines changed: 30 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -580,14 +580,40 @@ StreamLogicalLog(void)
580580
res = PQgetResult(conn);
581581
if (PQresultStatus(res) == PGRES_COPY_OUT)
582582
{
583+
PQclear(res);
584+
583585
/*
584586
* We're doing a client-initiated clean exit and have sent CopyDone to
585-
* the server. We've already sent replay confirmation and fsync'd so
586-
* we can just clean up the connection now.
587+
* the server. Drain any messages, so we don't miss a last-minute
588+
* ErrorResponse. The walsender stops generating XLogData records once
589+
* it sees CopyDone, so expect this to finish quickly. After CopyDone,
590+
* it's too late for sendFeedback(), even if this were to take a long
591+
* time. Hence, use synchronous-mode PQgetCopyData().
587592
*/
588-
goto error;
593+
while (1)
594+
{
595+
int r;
596+
597+
if (copybuf != NULL)
598+
{
599+
PQfreemem(copybuf);
600+
copybuf = NULL;
601+
}
602+
r = PQgetCopyData(conn, &copybuf, 0);
603+
if (r == -1)
604+
break;
605+
if (r == -2)
606+
{
607+
pg_log_error("could not read COPY data: %s",
608+
PQerrorMessage(conn));
609+
time_to_abort = false; /* unclean exit */
610+
goto error;
611+
}
612+
}
613+
614+
res = PQgetResult(conn);
589615
}
590-
else if (PQresultStatus(res) != PGRES_COMMAND_OK)
616+
if (PQresultStatus(res) != PGRES_COMMAND_OK)
591617
{
592618
pg_log_error("unexpected termination of replication stream: %s",
593619
PQresultErrorMessage(res));

src/test/recovery/t/006_logical_decoding.pl

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@
7171
);
7272
print "waiting to replay $endpos\n";
7373

74+
# Insert some rows after $endpos, which we won't read.
75+
$node_master->safe_psql('postgres',
76+
qq[INSERT INTO decoding_test(x,y) SELECT s, s::text FROM generate_series(5,50) s;]
77+
);
78+
7479
my $stdout_recv = $node_master->pg_recvlogical_upto(
7580
'postgres', 'test_slot', $endpos, 180,
7681
'include-xids' => '0',
@@ -89,7 +94,7 @@
8994
'skip-empty-xacts' => '1');
9095
chomp($stdout_recv);
9196
is($stdout_recv, '',
92-
'pg_recvlogical acknowledged changes, nothing pending on slot');
97+
'pg_recvlogical acknowledged changes');
9398

9499
$node_master->safe_psql('postgres', 'CREATE DATABASE otherdb');
95100

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy