*** a/doc/src/sgml/config.sgml
--- b/doc/src/sgml/config.sgml
***************
*** 2152,2161 **** SET ENABLE_SEQSCAN TO OFF;
         </listitem>
        </varlistentry>
  
!      <varlistentry id="guc-replication-timeout" xreflabel="replication_timeout">
!       <term><varname>replication_timeout</varname> (<type>integer</type>)</term>
        <indexterm>
!        <primary><varname>replication_timeout</> configuration parameter</primary>
        </indexterm>
        <listitem>
         <para>
--- 2152,2161 ----
         </listitem>
        </varlistentry>
  
!      <varlistentry id="guc-wal-sender-timeout" xreflabel="wal_sender_timeout">
!       <term><varname>wal_sender_timeout</varname> (<type>integer</type>)</term>
        <indexterm>
!        <primary><varname>wal_sender_timeout</> configuration parameter</primary>
        </indexterm>
        <listitem>
         <para>
***************
*** 2167,2177 **** SET ENABLE_SEQSCAN TO OFF;
          the <filename>postgresql.conf</> file or on the server command line.
          The default value is 60 seconds.
         </para>
         <para>
!         To prevent connections from being terminated prematurely,
!         <xref linkend="guc-wal-receiver-status-interval">
!         must be enabled on the standby, and its value must be less than the
!         value of <varname>replication_timeout</>.
         </para>
        </listitem>
       </varlistentry>
--- 2167,2189 ----
          the <filename>postgresql.conf</> file or on the server command line.
          The default value is 60 seconds.
         </para>
+       </listitem>
+      </varlistentry>
+ 	 
+ 	 <varlistentry id="guc-wal-receiver-timeout" xreflabel="wal_receiver_timeout">
+       <term><varname>wal_receiver_timeout</varname> (<type>integer</type>)</term>
+       <indexterm>
+        <primary><varname>wal_receiver_timeout</> configuration parameter</primary>
+       </indexterm>
+       <listitem>
         <para>
!         Terminate replication connections that are inactive longer
!         than the specified number of milliseconds. This is useful for
!         the receiving standby server to detect a primary node crash or network outage.
!         A value of zero disables the timeout mechanism.  This parameter
!         can only be set in
!         the <filename>postgresql.conf</> file or on the server command line.
!         The default value is 60 seconds.
         </para>
        </listitem>
       </varlistentry>
***************
*** 2390,2400 **** SET ENABLE_SEQSCAN TO OFF;
         the <filename>postgresql.conf</> file or on the server command line.
         The default value is 10 seconds.
        </para>
-       <para>
-        When <xref linkend="guc-replication-timeout"> is enabled on a sending server,
-        <varname>wal_receiver_status_interval</> must be enabled, and its value
-        must be less than the value of <varname>replication_timeout</>.
-       </para>
        </listitem>
       </varlistentry>
  
--- 2402,2407 ----
*** a/src/backend/replication/walreceiver.c
--- b/src/backend/replication/walreceiver.c
***************
*** 38,43 ****
--- 38,44 ----
  #include <signal.h>
  #include <unistd.h>
  
+ #include "access/transam.h"
  #include "access/xlog_internal.h"
  #include "libpq/pqsignal.h"
  #include "miscadmin.h"
***************
*** 62,67 **** walrcv_connect_type walrcv_connect = NULL;
--- 63,70 ----
  walrcv_receive_type walrcv_receive = NULL;
  walrcv_send_type walrcv_send = NULL;
  walrcv_disconnect_type walrcv_disconnect = NULL;
+ int			wal_receiver_timeout = 60 * 1000;	/* maximum time to receive one
+ 												 * WAL data message */
  
  #define NAPTIME_PER_CYCLE 100	/* max sleep time between cycles (100ms) */
  
***************
*** 121,127 **** static void WalRcvDie(int code, Datum arg);
  static void XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len);
  static void XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr);
  static void XLogWalRcvFlush(bool dying);
! static void XLogWalRcvSendReply(void);
  static void XLogWalRcvSendHSFeedback(void);
  static void ProcessWalSndrMessage(XLogRecPtr walEnd, TimestampTz sendTime);
  
--- 124,130 ----
  static void XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len);
  static void XLogWalRcvWrite(char *buf, Size nbytes, XLogRecPtr recptr);
  static void XLogWalRcvFlush(bool dying);
! static void XLogWalRcvSendReply(bool sendImmediate);
  static void XLogWalRcvSendHSFeedback(void);
  static void ProcessWalSndrMessage(XLogRecPtr walEnd, TimestampTz sendTime);
  
***************
*** 174,179 **** WalReceiverMain(void)
--- 177,185 ----
  	/* use volatile pointer to prevent code rearrangement */
  	volatile WalRcvData *walrcv = WalRcv;
  
+ 	TimestampTz last_recv_timestamp;
+ 	TimestampTz timeout = 0;
+ 
  	/*
  	 * WalRcv should be set up already (if we are a backend, we inherit this
  	 * by fork() or EXEC_BACKEND mechanism from the postmaster).
***************
*** 282,287 **** WalReceiverMain(void)
--- 288,296 ----
  	MemSet(&reply_message, 0, sizeof(reply_message));
  	MemSet(&feedback_message, 0, sizeof(feedback_message));
  
+ 	/* Initialize the last recv timestamp */
+ 	last_recv_timestamp = GetCurrentTimestamp();
+ 
  	/* Loop until end-of-streaming or error */
  	for (;;)
  	{
***************
*** 316,330 **** WalReceiverMain(void)
  		/* Wait a while for data to arrive */
  		if (walrcv_receive(NAPTIME_PER_CYCLE, &type, &buf, &len))
  		{
  			/* Accept the received data, and process it */
  			XLogWalRcvProcessMsg(type, buf, len);
  
  			/* Receive any more data we can without sleeping */
  			while (walrcv_receive(0, &type, &buf, &len))
  				XLogWalRcvProcessMsg(type, buf, len);
  
  			/* Let the master know that we received some data. */
! 			XLogWalRcvSendReply();
  
  			/*
  			 * If we've written some records, flush them to disk and let the
--- 325,347 ----
  		/* Wait a while for data to arrive */
  		if (walrcv_receive(NAPTIME_PER_CYCLE, &type, &buf, &len))
  		{
+ 			/* Something is received from master, so reset last receive time*/
+ 			last_recv_timestamp = GetCurrentTimestamp();
+ 			
  			/* Accept the received data, and process it */
  			XLogWalRcvProcessMsg(type, buf, len);
  
  			/* Receive any more data we can without sleeping */
  			while (walrcv_receive(0, &type, &buf, &len))
+ 			{
+ 				/* Something is received from master, so reset last receive time*/
+ 				last_recv_timestamp = GetCurrentTimestamp();
+ 				
  				XLogWalRcvProcessMsg(type, buf, len);
+ 			}
  
  			/* Let the master know that we received some data. */
! 			XLogWalRcvSendReply(false);
  
  			/*
  			 * If we've written some records, flush them to disk and let the
***************
*** 334,345 **** WalReceiverMain(void)
  		}
  		else
  		{
! 			/*
! 			 * We didn't receive anything new, but send a status update to the
! 			 * master anyway, to report any progress in applying WAL.
! 			 */
! 			XLogWalRcvSendReply();
! 			XLogWalRcvSendHSFeedback();
  		}
  	}
  }
--- 351,380 ----
  		}
  		else
  		{
! 			/* Check if time since last receive from standby has reached the configured limit
! 			 * No need to check if it is disabled by giving value as 0*/
! 			if (wal_receiver_timeout > 0)
! 			{
! 				timeout = TimestampTzPlusMilliseconds(last_recv_timestamp,
! 														  wal_receiver_timeout);
! 
! 				if (GetCurrentTimestamp() >= timeout)
! 				{
! 					ereport(ERROR,
! 						(errmsg("Could not receive any message from WalSender for configured timeout period")));
! 				}
! 
! 				/*
! 				 * We didn't receive anything new, for half of receiver replication timeout.
! 				 */
! 				timeout = TimestampTzPlusMilliseconds(last_recv_timestamp,
! 														  (wal_receiver_timeout/2));
! 
! 				if (GetCurrentTimestamp() >= timeout)
! 				{
! 					XLogWalRcvSendHSFeedback();
! 				}								
! 			}		
  		}
  	}
  }
***************
*** 460,465 **** XLogWalRcvProcessMsg(unsigned char type, char *buf, Size len)
--- 495,506 ----
  				memcpy(&keepalive, buf, sizeof(PrimaryKeepaliveMessage));
  
  				ProcessWalSndrMessage(keepalive.walEnd, keepalive.sendTime);
+ 
+ 				/* For heart-beat message from primary, send an immediate reply*/
+ 				if (keepalive.msgType != 'r')
+ 				{
+ 					XLogWalRcvSendReply(true);
+ 				}				
  				break;
  			}
  		default:
***************
*** 610,636 **** XLogWalRcvFlush(bool dying)
  		/* Also let the master know that we made some progress */
  		if (!dying)
  		{
! 			XLogWalRcvSendReply();
! 			XLogWalRcvSendHSFeedback();
  		}
  	}
  }
  
  /*
!  * Send reply message to primary, indicating our current XLOG positions and
!  * the current time.
   */
  static void
! XLogWalRcvSendReply(void)
  {
  	char		buf[sizeof(StandbyReplyMessage) + 1];
  	TimestampTz now;
  
  	/*
  	 * If the user doesn't want status to be reported to the master, be sure
  	 * to exit before doing anything at all.
  	 */
! 	if (wal_receiver_status_interval <= 0)
  		return;
  
  	/* Get current timestamp. */
--- 651,684 ----
  		/* Also let the master know that we made some progress */
  		if (!dying)
  		{
! 			XLogWalRcvSendReply(false);
  		}
  	}
  }
  
  /*
!  * Send reply message to primary, indicating our current XLOG positions, oldest
!  * xmin and the current time.
!  * The parameter sendImmediate is used to decide whether the reply has to be 
!  *  send immediately or after wal_receiver_status_interval.
!  * If the reply is getting sent because of heart-beat from primary, then this param
!  * should be true otherwise false.
   */
  static void
! XLogWalRcvSendReply(bool sendImmediate)
  {
  	char		buf[sizeof(StandbyReplyMessage) + 1];
  	TimestampTz now;
+ 	TransactionId nextXid;
+ 	uint32		nextEpoch;
+ 	TransactionId xmin;
+ 	
  
  	/*
  	 * If the user doesn't want status to be reported to the master, be sure
  	 * to exit before doing anything at all.
  	 */
! 	if (!sendImmediate && wal_receiver_status_interval <= 0)
  		return;
  
  	/* Get current timestamp. */
***************
*** 645,651 **** XLogWalRcvSendReply(void)
  	 * this is only for reporting purposes and only on idle systems, that's
  	 * probably OK.
  	 */
! 	if (XLByteEQ(reply_message.write, LogstreamResult.Write)
  		&& XLByteEQ(reply_message.flush, LogstreamResult.Flush)
  		&& !TimestampDifferenceExceeds(reply_message.sendTime, now,
  									   wal_receiver_status_interval * 1000))
--- 693,700 ----
  	 * this is only for reporting purposes and only on idle systems, that's
  	 * probably OK.
  	 */
! 	if (!sendImmediate
! 		&& XLByteEQ(reply_message.write, LogstreamResult.Write)
  		&& XLByteEQ(reply_message.flush, LogstreamResult.Flush)
  		&& !TimestampDifferenceExceeds(reply_message.sendTime, now,
  									   wal_receiver_status_interval * 1000))
***************
*** 654,660 **** XLogWalRcvSendReply(void)
  	/* Construct a new message */
  	reply_message.write = LogstreamResult.Write;
  	reply_message.flush = LogstreamResult.Flush;
! 	reply_message.apply = GetXLogReplayRecPtr(NULL);
  	reply_message.sendTime = now;
  
  	elog(DEBUG2, "sending write %X/%X flush %X/%X apply %X/%X",
--- 703,709 ----
  	/* Construct a new message */
  	reply_message.write = LogstreamResult.Write;
  	reply_message.flush = LogstreamResult.Flush;
! 	reply_message.apply = GetXLogReplayRecPtr(NULL);	
  	reply_message.sendTime = now;
  
  	elog(DEBUG2, "sending write %X/%X flush %X/%X apply %X/%X",
***************
*** 662,667 **** XLogWalRcvSendReply(void)
--- 711,749 ----
  		 (uint32) (reply_message.flush >> 32), (uint32) reply_message.flush,
  		 (uint32) (reply_message.apply >> 32), (uint32) reply_message.apply);
  
+ 	if (hot_standby_feedback && HotStandbyActive())
+ 	{
+ 		/*
+ 		 * Make the expensive call to get the oldest xmin once we are certain
+ 		 * everything else has been checked.
+ 		 */
+ 		xmin = GetOldestXmin(true, false);
+ 
+ 		/*
+ 		 * Get epoch and adjust if nextXid and oldestXmin are different sides of
+ 		 * the epoch boundary.
+ 		 */
+ 		GetNextXidAndEpoch(&nextXid, &nextEpoch);
+ 		if (nextXid < xmin)
+ 			nextEpoch--;
+ 
+ 		/*
+ 		 * Always send feedback message.
+ 		 */
+ 		reply_message.xmin = xmin;
+ 		reply_message.epoch = nextEpoch;
+ 
+ 		elog(DEBUG2, "sending hot standby feedback xmin %u epoch %u",
+ 			 reply_message.xmin,
+ 			 reply_message.epoch);	
+ 	}
+ 	else
+ 	{
+ 		/* Mark xmin invalid so that while primary node process this message it
+ 		  * can find out that xmin and epoch are not sent as part of reply*/
+ 		reply_message.xmin = InvalidTransactionId;
+ 	}
+ 
  	/* Prepend with the message type and send it. */
  	buf[0] = 'r';
  	memcpy(&buf[1], &reply_message, sizeof(StandbyReplyMessage));
***************
*** 681,734 **** XLogWalRcvSendHSFeedback(void)
  	uint32		nextEpoch;
  	TransactionId xmin;
  
- 	/*
- 	 * If the user doesn't want status to be reported to the master, be sure
- 	 * to exit before doing anything at all.
- 	 */
- 	if (wal_receiver_status_interval <= 0 || !hot_standby_feedback)
- 		return;
- 
  	/* Get current timestamp. */
  	now = GetCurrentTimestamp();
  
  	/*
- 	 * Send feedback at most once per wal_receiver_status_interval.
- 	 */
- 	if (!TimestampDifferenceExceeds(feedback_message.sendTime, now,
- 									wal_receiver_status_interval * 1000))
- 		return;
- 
- 	/*
- 	 * 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 (!HotStandbyActive())
- 		return;
- 
- 	/*
- 	 * Make the expensive call to get the oldest xmin once we are certain
- 	 * everything else has been checked.
- 	 */
- 	xmin = GetOldestXmin(true, false);
- 
- 	/*
- 	 * Get epoch and adjust if nextXid and oldestXmin are different sides of
- 	 * the epoch boundary.
- 	 */
- 	GetNextXidAndEpoch(&nextXid, &nextEpoch);
- 	if (nextXid < xmin)
- 		nextEpoch--;
- 
- 	/*
  	 * Always send feedback message.
  	 */
  	feedback_message.sendTime = now;
- 	feedback_message.xmin = xmin;
- 	feedback_message.epoch = nextEpoch;
- 
- 	elog(DEBUG2, "sending hot standby feedback xmin %u epoch %u",
- 		 feedback_message.xmin,
- 		 feedback_message.epoch);
  
  	/* Prepend with the message type and send it. */
  	buf[0] = 'h';
--- 763,775 ----
*** a/src/backend/replication/walsender.c
--- b/src/backend/replication/walsender.c
***************
*** 80,86 **** bool		am_cascading_walsender = false;		/* Am I cascading WAL to
  
  /* User-settable parameters for walsender */
  int			max_wal_senders = 0;	/* the maximum number of concurrent walsenders */
! int			replication_timeout = 60 * 1000;	/* maximum time to send one
  												 * WAL data message */
  /*
   * State for WalSndWakeupRequest
--- 80,86 ----
  
  /* User-settable parameters for walsender */
  int			max_wal_senders = 0;	/* the maximum number of concurrent walsenders */
! int			wal_sender_timeout = 60 * 1000;	/* maximum time to send one
  												 * WAL data message */
  /*
   * State for WalSndWakeupRequest
***************
*** 132,142 **** static void WalSndKill(int code, Datum arg);
  static void XLogSend(char *msgbuf, bool *caughtup);
  static void IdentifySystem(void);
  static void StartReplication(StartReplicationCmd *cmd);
! static void ProcessStandbyMessage(void);
  static void ProcessStandbyReplyMessage(void);
! static void ProcessStandbyHSFeedbackMessage(void);
! static void ProcessRepliesIfAny(void);
! static void WalSndKeepalive(char *msgbuf);
  
  
  /* Main entry point for walsender process */
--- 132,142 ----
  static void XLogSend(char *msgbuf, bool *caughtup);
  static void IdentifySystem(void);
  static void StartReplication(StartReplicationCmd *cmd);
! static void ProcessStandbyMessage(char *output_message);
  static void ProcessStandbyReplyMessage(void);
! static void ProcessStandbyTransInfo(StandbyReplyMessage reply);
! static void ProcessRepliesIfAny(char *output_message);
! static void WalSndKeepalive(char *msgbuf, bool isReply);
  
  
  /* Main entry point for walsender process */
***************
*** 507,513 **** HandleReplicationCommand(const char *cmd_string)
   * Check if the remote end has closed the connection.
   */
  static void
! ProcessRepliesIfAny(void)
  {
  	unsigned char firstchar;
  	int			r;
--- 507,513 ----
   * Check if the remote end has closed the connection.
   */
  static void
! ProcessRepliesIfAny(char *output_message)
  {
  	unsigned char firstchar;
  	int			r;
***************
*** 537,543 **** ProcessRepliesIfAny(void)
  				 * 'd' means a standby reply wrapped in a CopyData packet.
  				 */
  			case 'd':
! 				ProcessStandbyMessage();
  				received = true;
  				break;
  
--- 537,543 ----
  				 * 'd' means a standby reply wrapped in a CopyData packet.
  				 */
  			case 'd':
! 				ProcessStandbyMessage(output_message);
  				received = true;
  				break;
  
***************
*** 566,572 **** ProcessRepliesIfAny(void)
   * Process a status update message received from standby.
   */
  static void
! ProcessStandbyMessage(void)
  {
  	char		msgtype;
  
--- 566,572 ----
   * Process a status update message received from standby.
   */
  static void
! ProcessStandbyMessage(char *output_message)
  {
  	char		msgtype;
  
***************
*** 595,601 **** ProcessStandbyMessage(void)
  			break;
  
  		case 'h':
! 			ProcessStandbyHSFeedbackMessage();
  			break;
  
  		default:
--- 595,605 ----
  			break;
  
  		case 'h':
! 			/* 
! 			  * Once this message is received, we should send an immediate reply 
! 			  * to standby node in order to indicate connection is alive
! 			  */
! 			WalSndKeepalive(output_message, true);
  			break;
  
  		default:
***************
*** 607,613 **** ProcessStandbyMessage(void)
  }
  
  /*
!  * Regular reply from standby advising of WAL positions on standby server.
   */
  static void
  ProcessStandbyReplyMessage(void)
--- 611,617 ----
  }
  
  /*
!  * Regular reply from standby advising of WAL positions and transaction on standby server.
   */
  static void
  ProcessStandbyReplyMessage(void)
***************
*** 636,659 **** ProcessStandbyReplyMessage(void)
  		SpinLockRelease(&walsnd->mutex);
  	}
  
  	if (!am_cascading_walsender)
  		SyncRepReleaseWaiters();
  }
  
  /*
!  * Hot Standby feedback
   */
  static void
! ProcessStandbyHSFeedbackMessage(void)
  {
- 	StandbyHSFeedbackMessage reply;
  	TransactionId nextXid;
  	uint32		nextEpoch;
  
- 	/* Decipher the reply message */
- 	pq_copymsgbytes(&reply_message, (char *) &reply,
- 					sizeof(StandbyHSFeedbackMessage));
- 
  	elog(DEBUG2, "hot standby feedback xmin %u epoch %u",
  		 reply.xmin,
  		 reply.epoch);
--- 640,660 ----
  		SpinLockRelease(&walsnd->mutex);
  	}
  
+ 	ProcessStandbyTransInfo(reply);
+ 
  	if (!am_cascading_walsender)
  		SyncRepReleaseWaiters();
  }
  
  /*
!  * Stores the transaction info received from standby
   */
  static void
! ProcessStandbyTransInfo(StandbyReplyMessage reply)
  {
  	TransactionId nextXid;
  	uint32		nextEpoch;
  
  	elog(DEBUG2, "hot standby feedback xmin %u epoch %u",
  		 reply.xmin,
  		 reply.epoch);
***************
*** 765,771 **** WalSndLoop(void)
  		}
  
  		/* Check for input from the client */
! 		ProcessRepliesIfAny();
  
  		/*
  		 * If we don't have any pending data in the output buffer, try to send
--- 766,772 ----
  		}
  
  		/* Check for input from the client */
! 		ProcessRepliesIfAny(output_message);
  
  		/*
  		 * If we don't have any pending data in the output buffer, try to send
***************
*** 835,856 **** WalSndLoop(void)
  			wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
  				WL_SOCKET_READABLE | WL_TIMEOUT;
  
  			if (pq_is_send_pending())
  				wakeEvents |= WL_SOCKET_WRITEABLE;
! 			else if (MyWalSnd->sendKeepalive)
  			{
! 				WalSndKeepalive(output_message);
  				/* Try to flush pending output to the client */
  				if (pq_flush_if_writable() != 0)
  					break;
  			}
  
  			/* Determine time until replication timeout */
! 			if (replication_timeout > 0)
  			{
  				timeout = TimestampTzPlusMilliseconds(last_reply_timestamp,
! 													  replication_timeout);
! 				sleeptime = 1 + (replication_timeout / 10);
  			}
  
  			/* Sleep until something happens or replication timeout */
--- 836,867 ----
  			wakeEvents = WL_LATCH_SET | WL_POSTMASTER_DEATH |
  				WL_SOCKET_READABLE | WL_TIMEOUT;
  
+ 			/*
+ 			  * Check if half of wal_sender_timeout has lapsed without receiving any reply from standby
+ 			  * then send a keep-alive message to standby to detect standby status
+ 			  */
+ 			timeout = TimestampTzPlusMilliseconds(last_reply_timestamp,
+ 												  (wal_sender_timeout/2));
+ 			/* 
+ 			  * send keepalive message if sendkeepalive is enabled or WAL send status 
+ 			  * interval is greater than zero.
+ 			  */
  			if (pq_is_send_pending())
  				wakeEvents |= WL_SOCKET_WRITEABLE;
! 			else if (MyWalSnd->sendKeepalive || (wal_sender_timeout > 0 && GetCurrentTimestamp() >= timeout))
  			{
! 				WalSndKeepalive(output_message, false);
  				/* Try to flush pending output to the client */
  				if (pq_flush_if_writable() != 0)
  					break;
  			}
  
  			/* Determine time until replication timeout */
! 			if (wal_sender_timeout > 0)
  			{
  				timeout = TimestampTzPlusMilliseconds(last_reply_timestamp,
! 													  wal_sender_timeout);
! 				sleeptime = 1 + (wal_sender_timeout / 10);
  			}
  
  			/* Sleep until something happens or replication timeout */
***************
*** 862,868 **** WalSndLoop(void)
  			 * possibility that the client replied just as we reached the
  			 * timeout ... he's supposed to reply *before* that.
  			 */
! 			if (replication_timeout > 0 &&
  				GetCurrentTimestamp() >= timeout)
  			{
  				/*
--- 873,879 ----
  			 * possibility that the client replied just as we reached the
  			 * timeout ... he's supposed to reply *before* that.
  			 */
! 			if (wal_sender_timeout > 0 &&
  				GetCurrentTimestamp() >= timeout)
  			{
  				/*
***************
*** 1617,1630 **** pg_stat_get_wal_senders(PG_FUNCTION_ARGS)
  	return (Datum) 0;
  }
  
  static void
! WalSndKeepalive(char *msgbuf)
  {
  	PrimaryKeepaliveMessage keepalive_message;
  
  	/* Construct a new message */
  	keepalive_message.walEnd = sentPtr;
  	keepalive_message.sendTime = GetCurrentTimestamp();
  
  	elog(DEBUG2, "sending replication keepalive");
  
--- 1628,1655 ----
  	return (Datum) 0;
  }
  
+ /* 
+   * This function is used to send keepalive message to standby.
+   * Depending on the parameter isReply value as true or false,
+   * it sends reply or heart-beat message to standby respectively
+   */
+  
  static void
! WalSndKeepalive(char *msgbuf, bool isReply)
  {
  	PrimaryKeepaliveMessage keepalive_message;
  
  	/* Construct a new message */
  	keepalive_message.walEnd = sentPtr;
  	keepalive_message.sendTime = GetCurrentTimestamp();
+ 	if (isReply)
+ 	{
+ 		keepalive_message.msgType = 'r';
+ 	}
+ 	else
+ 	{
+ 		keepalive_message.msgType = 'h';
+ 	}
  
  	elog(DEBUG2, "sending replication keepalive");
  
*** a/src/backend/utils/misc/guc.c
--- b/src/backend/utils/misc/guc.c
***************
*** 1596,1601 **** static struct config_int ConfigureNamesInt[] =
--- 1596,1612 ----
  	},
  
  	{
+ 		{"wal_receiver_timeout", PGC_SIGHUP, REPLICATION_STANDBY,
+ 			gettext_noop("Sets the maximum wait time to receive data from master."),
+ 			NULL,
+ 			GUC_UNIT_MS
+ 		},
+ 		&wal_receiver_timeout,
+ 		60 * 1000, 0, INT_MAX,
+ 		NULL, NULL, NULL
+ 	},
+ 
+ 	{
  		{"max_connections", PGC_POSTMASTER, CONN_AUTH_SETTINGS,
  			gettext_noop("Sets the maximum number of concurrent connections."),
  			NULL
***************
*** 2019,2030 **** static struct config_int ConfigureNamesInt[] =
  	},
  
  	{
! 		{"replication_timeout", PGC_SIGHUP, REPLICATION_SENDING,
  			gettext_noop("Sets the maximum time to wait for WAL replication."),
  			NULL,
  			GUC_UNIT_MS
  		},
! 		&replication_timeout,
  		60 * 1000, 0, INT_MAX,
  		NULL, NULL, NULL
  	},
--- 2030,2041 ----
  	},
  
  	{
! 		{"wal_sender_timeout", PGC_SIGHUP, REPLICATION_SENDING,
  			gettext_noop("Sets the maximum time to wait for WAL replication."),
  			NULL,
  			GUC_UNIT_MS
  		},
! 		&wal_sender_timeout,
  		60 * 1000, 0, INT_MAX,
  		NULL, NULL, NULL
  	},
***************
*** 2381,2387 **** static struct config_int ConfigureNamesInt[] =
  		1024, 100, 102400,
  		NULL, NULL, NULL
  	},
! 
  	/* End-of-list marker */
  	{
  		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
--- 2392,2398 ----
  		1024, 100, 102400,
  		NULL, NULL, NULL
  	},
! 		
  	/* End-of-list marker */
  	{
  		{NULL, 0, 0, NULL, NULL}, NULL, 0, 0, 0, NULL, NULL, NULL
*** a/src/backend/utils/misc/postgresql.conf.sample
--- b/src/backend/utils/misc/postgresql.conf.sample
***************
*** 210,216 ****
  #max_wal_senders = 0		# max number of walsender processes
  				# (change requires restart)
  #wal_keep_segments = 0		# in logfile segments, 16MB each; 0 disables
! #replication_timeout = 60s	# in milliseconds; 0 disables
  
  # - Master Server -
  
--- 210,216 ----
  #max_wal_senders = 0		# max number of walsender processes
  				# (change requires restart)
  #wal_keep_segments = 0		# in logfile segments, 16MB each; 0 disables
! #wal_sender_timeout = 60s	# in milliseconds; 0 disables
  
  # - Master Server -
  
***************
*** 234,242 ****
  					# when reading streaming WAL;
  					# -1 allows indefinite delay
  #wal_receiver_status_interval = 10s	# send replies at least this often
! 					# 0 disables
  #hot_standby_feedback = off		# send info from standby to prevent
  					# query conflicts
  
  
  #------------------------------------------------------------------------------
--- 234,244 ----
  					# when reading streaming WAL;
  					# -1 allows indefinite delay
  #wal_receiver_status_interval = 10s	# send replies at least this often
! 					# in seconds; 0 disables
  #hot_standby_feedback = off		# send info from standby to prevent
  					# query conflicts
+ #wal_receiver_timeout = 60s	# in milliseconds; 0 disables; time 
+ 					# till receiver waits for communication from master.
  
  
  #------------------------------------------------------------------------------
*** a/src/include/replication/walprotocol.h
--- b/src/include/replication/walprotocol.h
***************
*** 27,32 **** typedef struct
--- 27,37 ----
  
  	/* Sender's system clock at the time of transmission */
  	TimestampTz sendTime;
+ 
+ 	/* This is the message type. If its type is r i.e. reply then it overrides the keepalive
+ 	 * and it serves the purpose of reply for heart-beat message from standby.
+ 	 */
+ 	char msgType; 
  } WalSndrMessage;
  
  
***************
*** 78,83 **** typedef struct
--- 83,102 ----
  	XLogRecPtr	flush;
  	XLogRecPtr	apply;
  
+ 	/* 
+ 	  * Transaction information (Earlier these field were used to be with HS Feedback 
+ 	  * message but now both of the messages are combined so combining structure
+ 	  * members also
+ 	  */
+ 	/*
+ 	 * The current xmin and epoch from the standby, for Hot Standby feedback.
+ 	 * This may be invalid if the standby-side does not support feedback, or
+ 	 * Hot Standby is not yet available.
+ 	 */	  
+ 	TransactionId xmin;
+ 	uint32		epoch;
+ 	  
+ 
  	/* Sender's system clock at the time of transmission */
  	TimestampTz sendTime;
  } StandbyReplyMessage;
***************
*** 90,103 **** typedef struct
   */
  typedef struct
  {
- 	/*
- 	 * The current xmin and epoch from the standby, for Hot Standby feedback.
- 	 * This may be invalid if the standby-side does not support feedback, or
- 	 * Hot Standby is not yet available.
- 	 */
- 	TransactionId xmin;
- 	uint32		epoch;
- 
  	/* Sender's system clock at the time of transmission */
  	TimestampTz sendTime;
  } StandbyHSFeedbackMessage;
--- 109,114 ----
*** a/src/include/replication/walreceiver.h
--- b/src/include/replication/walreceiver.h
***************
*** 19,24 ****
--- 19,25 ----
  
  extern int	wal_receiver_status_interval;
  extern bool hot_standby_feedback;
+ extern int wal_receiver_timeout;
  
  /*
   * MAXCONNINFO: maximum size of a connection string.
*** a/src/include/replication/walsender.h
--- b/src/include/replication/walsender.h
***************
*** 25,31 **** extern bool wake_wal_senders;
  
  /* user-settable parameters */
  extern int	max_wal_senders;
! extern int	replication_timeout;
  
  extern void WalSenderMain(void) __attribute__((noreturn));
  extern void WalSndSignals(void);
--- 25,31 ----
  
  /* user-settable parameters */
  extern int	max_wal_senders;
! extern int	wal_sender_timeout;
  
  extern void WalSenderMain(void) __attribute__((noreturn));
  extern void WalSndSignals(void);
