On Thu, Jul 28, 2016 at 9:08 PM, Fujii Masao <masao.fu...@gmail.com> wrote:
> On Thu, Jul 28, 2016 at 6:52 PM, Kyotaro HORIGUCHI
> <horiguchi.kyot...@lab.ntt.co.jp> wrote:
>> Hello,
>>
>> While testing replication for 9.5, we found that repl-master can
>> ignore wal_sender_timeout and seemingly waits for TCP
>> retransmission timeout for the case of sudden power-off of a
>> standby.
>>
>> My investigation told me that the immediate cause could be that
>> secure_write() is called with *blocking mode* (that is,
>> port->noblock = false) under *pq_putmessage_noblock* macro called
>> from XLogSendPhysical().
>>
>> libpq.h of 9.5 and newer defines it as the following,
>>
>>> #define pq_putmessage(msgtype, s, len) \
>>>       (PqCommMethods->putmessage(msgtype, s, len))
>>> #define pq_putmessage_noblock(msgtype, s, len) \
>>>       (PqCommMethods->putmessage(msgtype, s, len))
>>
>> which is apparently should be the following.
>>
>>> #define pq_putmessage_noblock(msgtype, s, len) \
>>>       (PqCommMethods->putmessage_noblock(msgtype, s, len))
>>
>> The attached patch fixes it.
>
> Good catch! Barring objection, I will push this to both master and 9.5.

Regarding this patch, while reading pqcomm.c, I found the following things.

1. socket_comm_reset() calls pq_endcopyout().
    I think that socket_endcopyout() should be called, instead.

2. socket_putmessage_noblock() calls pq_putmessage().
    I think that socket_putmessage() should be called, instead.

3. Several source comments in pqcomm.c have not been updated.
    Some comments still use the old function name like pq_putmessage().

Attached patch fixes the above issues.

Regards,

-- 
Fujii Masao
*** a/src/backend/libpq/pqcomm.c
--- b/src/backend/libpq/pqcomm.c
***************
*** 18,24 ****
   * NOTE: generally, it's a bad idea to emit outgoing messages directly with
   * pq_putbytes(), especially if the message would require multiple calls
   * to send.  Instead, use the routines in pqformat.c to construct the message
!  * in a buffer and then emit it in one call to pq_putmessage.  This ensures
   * that the channel will not be clogged by an incomplete message if execution
   * is aborted by ereport(ERROR) partway through the message.  The only
   * non-libpq code that should call pq_putbytes directly is old-style COPY OUT.
--- 18,24 ----
   * NOTE: generally, it's a bad idea to emit outgoing messages directly with
   * pq_putbytes(), especially if the message would require multiple calls
   * to send.  Instead, use the routines in pqformat.c to construct the message
!  * in a buffer and then emit it in one call to socket_putmessage.  This ensures
   * that the channel will not be clogged by an incomplete message if execution
   * is aborted by ereport(ERROR) partway through the message.  The only
   * non-libpq code that should call pq_putbytes directly is old-style COPY OUT.
***************
*** 44,50 ****
   *		StreamClose			- Close a client/backend connection
   *		TouchSocketFiles	- Protect socket files against /tmp cleaners
   *		pq_init			- initialize libpq at backend startup
!  *		pq_comm_reset	- reset libpq during error recovery
   *		pq_close		- shutdown libpq at backend exit
   *
   * low-level I/O:
--- 44,50 ----
   *		StreamClose			- Close a client/backend connection
   *		TouchSocketFiles	- Protect socket files against /tmp cleaners
   *		pq_init			- initialize libpq at backend startup
!  *		socket_comm_reset	- reset libpq during error recovery
   *		pq_close		- shutdown libpq at backend exit
   *
   * low-level I/O:
***************
*** 53,68 ****
   *		pq_getmessage	- get a message with length word from connection
   *		pq_getbyte		- get next byte from connection
   *		pq_peekbyte		- peek at next byte from connection
!  *		pq_putbytes		- send bytes to connection (not flushed until pq_flush)
!  *		pq_flush		- flush pending output
!  *		pq_flush_if_writable - flush pending output if writable without blocking
   *		pq_getbyte_if_available - get a byte if available without blocking
   *
   * message-level I/O (and old-style-COPY-OUT cruft):
!  *		pq_putmessage	- send a normal message (suppressed in COPY OUT mode)
!  *		pq_putmessage_noblock - buffer a normal message (suppressed in COPY OUT)
!  *		pq_startcopyout - inform libpq that a COPY OUT transfer is beginning
!  *		pq_endcopyout	- end a COPY OUT transfer
   *
   *------------------------
   */
--- 53,68 ----
   *		pq_getmessage	- get a message with length word from connection
   *		pq_getbyte		- get next byte from connection
   *		pq_peekbyte		- peek at next byte from connection
!  *		pq_putbytes		- send bytes to connection (not flushed until socket_flush)
!  *		socket_flush		- flush pending output
!  *		socket_flush_if_writable - flush pending output if writable without blocking
   *		pq_getbyte_if_available - get a byte if available without blocking
   *
   * message-level I/O (and old-style-COPY-OUT cruft):
!  *		socket_putmessage	- send a normal message (suppressed in COPY OUT mode)
!  *		socket_putmessage_noblock - buffer a normal message (suppressed in COPY OUT)
!  *		socket_startcopyout - inform libpq that a COPY OUT transfer is beginning
!  *		socket_endcopyout	- end a COPY OUT transfer
   *
   *------------------------
   */
***************
*** 109,115 **** static List *sock_paths = NIL;
   * Buffers for low-level I/O.
   *
   * The receive buffer is fixed size. Send buffer is usually 8k, but can be
!  * enlarged by pq_putmessage_noblock() if the message doesn't fit otherwise.
   */
  
  #define PQ_SEND_BUFFER_SIZE 8192
--- 109,115 ----
   * Buffers for low-level I/O.
   *
   * The receive buffer is fixed size. Send buffer is usually 8k, but can be
!  * enlarged by socket_putmessage_noblock() if the message doesn't fit otherwise.
   */
  
  #define PQ_SEND_BUFFER_SIZE 8192
***************
*** 223,229 **** socket_comm_reset(void)
  	/* Do not throw away pending data, but do reset the busy flag */
  	PqCommBusy = false;
  	/* We can abort any old-style COPY OUT, too */
! 	pq_endcopyout(true);
  }
  
  /* --------------------------------
--- 223,229 ----
  	/* Do not throw away pending data, but do reset the busy flag */
  	PqCommBusy = false;
  	/* We can abort any old-style COPY OUT, too */
! 	socket_endcopyout(true);
  }
  
  /* --------------------------------
***************
*** 1302,1308 **** pq_getmessage(StringInfo s, int maxlen)
  
  
  /* --------------------------------
!  *		pq_putbytes		- send bytes to connection (not flushed until pq_flush)
   *
   *		returns 0 if OK, EOF if trouble
   * --------------------------------
--- 1302,1308 ----
  
  
  /* --------------------------------
!  *		pq_putbytes		- send bytes to connection (not flushed until socket_flush)
   *
   *		returns 0 if OK, EOF if trouble
   * --------------------------------
***************
*** 1444,1450 **** internal_flush(void)
  }
  
  /* --------------------------------
!  *		pq_flush_if_writable - flush pending output if writable without blocking
   *
   * Returns 0 if OK, or EOF if trouble.
   * --------------------------------
--- 1444,1450 ----
  }
  
  /* --------------------------------
!  *		socket_flush_if_writable - flush pending output if writable without blocking
   *
   * Returns 0 if OK, or EOF if trouble.
   * --------------------------------
***************
*** 1542,1548 **** fail:
  }
  
  /* --------------------------------
!  *		pq_putmessage_noblock	- like pq_putmessage, but never blocks
   *
   *		If the output buffer is too small to hold the message, the buffer
   *		is enlarged.
--- 1542,1548 ----
  }
  
  /* --------------------------------
!  *		socket_putmessage_noblock	- like socket_putmessage, but never blocks
   *
   *		If the output buffer is too small to hold the message, the buffer
   *		is enlarged.
***************
*** 1563,1569 **** socket_putmessage_noblock(char msgtype, const char *s, size_t len)
  		PqSendBuffer = repalloc(PqSendBuffer, required);
  		PqSendBufferSize = required;
  	}
! 	res = pq_putmessage(msgtype, s, len);
  	Assert(res == 0);			/* should not fail when the message fits in
  								 * buffer */
  }
--- 1563,1569 ----
  		PqSendBuffer = repalloc(PqSendBuffer, required);
  		PqSendBufferSize = required;
  	}
! 	res = socket_putmessage(msgtype, s, len);
  	Assert(res == 0);			/* should not fail when the message fits in
  								 * buffer */
  }
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to