From ec4b975016b873292ba5e3d645b414acf1b96c06 Mon Sep 17 00:00:00 2001 From: Simon Riggs Date: Thu, 26 Jan 2017 18:14:02 +0000 Subject: [PATCH] Reset hot standby xmin on master after restart Hot_standby_feedback could be reset by reload and worked correctly, but if the server was restarted rather than reloaded the xmin was not reset. Force reset always if hot_standby_feedback is enabled at startup. Ants Aasma, Craig Ringer Reported-by: Ants Aasma --- src/backend/replication/walreceiver.c | 21 ++++++++++++++------- src/test/recovery/t/001_stream_rep.pl | 21 ++++++++++++++++++++- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/backend/replication/walreceiver.c b/src/backend/replication/walreceiver.c index 0e4a4b9d19..5c2e72ba9b 100644 --- a/src/backend/replication/walreceiver.c +++ b/src/backend/replication/walreceiver.c @@ -1167,7 +1167,10 @@ XLogWalRcvSendReply(bool force, bool requestReply) * in case they don't have a watch. * * If the user disables feedback, send one final message to tell sender - * to forget about the xmin on this standby. + * to forget about the xmin on this standby. We also send this message + * on first connect because a previous connection might have set xmin + * on a replication slot. (If we're not using a slot it's harmless to + * send a feedback message explicitly setting InvalidTransactionId). */ static void XLogWalRcvSendHSFeedback(bool immed) @@ -1177,7 +1180,8 @@ XLogWalRcvSendHSFeedback(bool immed) uint32 nextEpoch; TransactionId xmin; static TimestampTz sendTime = 0; - static bool master_has_standby_xmin = false; + /* initially true so we always send at least one feedback message */ + static bool master_has_standby_xmin = true; /* * If the user doesn't want status to be reported to the master, be sure @@ -1202,14 +1206,17 @@ XLogWalRcvSendHSFeedback(bool immed) } /* - * If Hot Standby is not yet active there is nothing to send. Check this - * after the interval has expired to reduce number of calls. + * If Hot Standby is not yet accepting connections there is nothing to + * send. Check this after the interval has expired to reduce number of + * calls. + * + * Bailing out here also ensures that we don't send feedback until we've + * read our own replication slot state, so we don't tell the master to + * discard needed xmin or catalog_xmin from any slots that may exist + * on this replica. */ if (!HotStandbyActive()) - { - Assert(!master_has_standby_xmin); return; - } /* * Make the expensive call to get the oldest xmin once we are certain diff --git a/src/test/recovery/t/001_stream_rep.pl b/src/test/recovery/t/001_stream_rep.pl index eef512d871..7fb2e9ecaa 100644 --- a/src/test/recovery/t/001_stream_rep.pl +++ b/src/test/recovery/t/001_stream_rep.pl @@ -3,7 +3,7 @@ use strict; use warnings; use PostgresNode; use TestLib; -use Test::More tests => 22; +use Test::More tests => 24; # Initialize master node my $node_master = get_new_node('master'); @@ -161,3 +161,22 @@ is($catalog_xmin, '', 'non-cascaded slot xmin still null with hs_feedback reset' ($xmin, $catalog_xmin) = get_slot_xmins($node_standby_1, $slotname_2); is($xmin, '', 'cascaded slot xmin null with hs feedback reset'); is($catalog_xmin, '', 'cascaded slot xmin still null with hs_feedback reset'); + +diag "re-enabling hot_standby_feedback and disabling while stopped"; +$node_standby_2->safe_psql('postgres', 'ALTER SYSTEM SET hot_standby_feedback = on;'); +$node_standby_2->reload; + +$node_master->safe_psql('postgres', qq[INSERT INTO tab_int VALUES (11000);]); +replay_check(); + +$node_standby_2->safe_psql('postgres', 'ALTER SYSTEM SET hot_standby_feedback = off;'); +$node_standby_2->stop; + +($xmin, $catalog_xmin) = get_slot_xmins($node_standby_1, $slotname_2); +isnt($xmin, '', 'cascaded slot xmin non-null with postgres shut down'); + +# Xmin from a previous run should be cleared on startup. +$node_standby_2->start; + +($xmin, $catalog_xmin) = get_slot_xmins($node_standby_1, $slotname_2); +is($xmin, '', 'cascaded slot xmin reset after startup with hs feedback reset'); -- 2.40.0