Small Bug in pgstat display during recovery conflict resolution

Started by Andres Freundalmost 16 years ago2 messages
#1Andres Freund
andres@anarazel.de
1 attachment(s)

Hi Simon, Hi all,

if (!logged && (wait_s > 0 || wait_us > 500000))
{
const char *oldactivitymsg;
int len;

oldactivitymsg = get_ps_display(&len);
snprintf(waitactivitymsg, sizeof(waitactivitymsg),
"waiting for max_standby_delay (%u s)",
MaxStandbyDelay);
set_ps_display(waitactivitymsg, false);
if (len > 100)
len = 100;
memcpy(waitactivitymsg, oldactivitymsg, len);

pgstat_report_waiting(true);

logged = true;
}
..
if (logged)
{
set_ps_display(waitactivitymsg, false);
pgstat_report_waiting(false);
}

That doesnt work because get_ps_display returns the internal buffer. This
leads to the situation that after conflict resolution the
"waiting for max_standby_delay ..."
message is displayed until the next segment starts where its replaced
again by the
"... recovering ..." line.

Additionally the old code may print unintialized memory if get_ps_display
returns a string without a \0 terminator.

The attached patch fixes that.

Andres

Attachments:

0001-The-stat-reporting-in-ResolveRecoveryConflictWithVir.patchtext/x-patch; charset=ISO-8859-1; name=0001-The-stat-reporting-in-ResolveRecoveryConflictWithVir.patchDownload
From a0198eab28552b9af9a70298f49a17348077c6fd Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Sun, 7 Feb 2010 19:52:07 +0100
Subject: [PATCH] The stat reporting in ResolveRecoveryConflictWithVirtualXIDs had a
 small bug - it tried to use the buffer returned by get_ps_display() as
 temp. storage - which does not work.

---
 src/backend/storage/ipc/standby.c |   17 +++++++++++------
 1 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/src/backend/storage/ipc/standby.c b/src/backend/storage/ipc/standby.c
index 63a9c68..995a2dc 100644
*** a/src/backend/storage/ipc/standby.c
--- b/src/backend/storage/ipc/standby.c
*************** ResolveRecoveryConflictWithVirtualXIDs(V
*** 161,166 ****
--- 161,167 ----
  									   ProcSignalReason reason)
  {
  	char		waitactivitymsg[100];
+ 	char		oldactivitymsg[101];
  
  	while (VirtualTransactionIdIsValid(*waitlist))
  	{
*************** ResolveRecoveryConflictWithVirtualXIDs(V
*** 183,199 ****
  			TimestampDifference(waitStart, now, &wait_s, &wait_us);
  			if (!logged && (wait_s > 0 || wait_us > 500000))
  			{
! 				const char *oldactivitymsg;
  				int			len;
  
! 				oldactivitymsg = get_ps_display(&len);
  				snprintf(waitactivitymsg, sizeof(waitactivitymsg),
  						 "waiting for max_standby_delay (%u s)",
  						 MaxStandbyDelay);
  				set_ps_display(waitactivitymsg, false);
- 				if (len > 100)
- 					len = 100;
- 				memcpy(waitactivitymsg, oldactivitymsg, len);
  
  				pgstat_report_waiting(true);
  
--- 184,204 ----
  			TimestampDifference(waitStart, now, &wait_s, &wait_us);
  			if (!logged && (wait_s > 0 || wait_us > 500000))
  			{
! 				const char *oldactivitymsgp;
  				int			len;
  
! 				oldactivitymsgp = get_ps_display(&len);
! 
! 				if (len > 100)
! 					len = 100;
! 
! 				memcpy(oldactivitymsg, oldactivitymsgp, len);
! 				oldactivitymsg[len] = 0;
! 
  				snprintf(waitactivitymsg, sizeof(waitactivitymsg),
  						 "waiting for max_standby_delay (%u s)",
  						 MaxStandbyDelay);
  				set_ps_display(waitactivitymsg, false);
  
  				pgstat_report_waiting(true);
  
*************** ResolveRecoveryConflictWithVirtualXIDs(V
*** 223,229 ****
  		/* Reset ps display */
  		if (logged)
  		{
! 			set_ps_display(waitactivitymsg, false);
  			pgstat_report_waiting(false);
  		}
  
--- 228,234 ----
  		/* Reset ps display */
  		if (logged)
  		{
! 			set_ps_display(oldactivitymsg, false);
  			pgstat_report_waiting(false);
  		}
  
-- 
1.6.5.12.gd65df24

#2Simon Riggs
simon@2ndQuadrant.com
In reply to: Andres Freund (#1)
Re: Small Bug in pgstat display during recovery conflict resolution

Committed, thanks.

On Sun, 2010-02-07 at 21:47 +0100, Andres Freund wrote:

Hi Simon, Hi all,

if (!logged && (wait_s > 0 || wait_us > 500000))
{
const char *oldactivitymsg;
int len;

oldactivitymsg = get_ps_display(&len);
snprintf(waitactivitymsg, sizeof(waitactivitymsg),
"waiting for max_standby_delay (%u s)",
MaxStandbyDelay);
set_ps_display(waitactivitymsg, false);
if (len > 100)
len = 100;
memcpy(waitactivitymsg, oldactivitymsg, len);

pgstat_report_waiting(true);

logged = true;
}
..
if (logged)
{
set_ps_display(waitactivitymsg, false);
pgstat_report_waiting(false);
}

That doesnt work because get_ps_display returns the internal buffer. This
leads to the situation that after conflict resolution the
"waiting for max_standby_delay ..."
message is displayed until the next segment starts where its replaced
again by the
"... recovering ..." line.

Additionally the old code may print unintialized memory if get_ps_display
returns a string without a \0 terminator.

The attached patch fixes that.

Andres

--
Simon Riggs www.2ndQuadrant.com