Thread

  1. [PATCH v2] pgbench: Fix assertion failure with multiple \syncpipeline in pipeline mode.

    Yugo Nagata <nagata@sraoss.co.jp> — 2025-11-11T01:14:30Z

    When running pgbench with a custom script that triggered retriable errors
    (e.g., deadlock errors) followed by multiple \syncpipeline commands in
    pipeline mode, an assertion failure could occur:
    
      pgbench.c:3594: discardUntilSync: Assertion `res == ((void *)0)' failed
    
    This happened because discardUntilSync() did not expect that a result
    other than NULL (e.g. PGRES_TUPLES_OK) might be received after \syncpipeline.
    
    This commit fixes the assertion failure by resetting the receive_sync flag
    and continueing to discard results to ensure that all results are discarded
    until the last sync point.
    
    Also, if the connection was unexpectedly closed, this function could get
    stuck in an infinite loop waiting for PGRES_PIPELINE_SYNC, which would never
    be received. To fix this, exit the loop immediately if a connection failure
    is detected.
    ---
     src/bin/pgbench/pgbench.c | 35 +++++++++++++++++++++++++----------
     1 file changed, 25 insertions(+), 10 deletions(-)
    
    diff --git a/src/bin/pgbench/pgbench.c b/src/bin/pgbench/pgbench.c
    index d8764ba6fe0..f165fabce36 100644
    --- a/src/bin/pgbench/pgbench.c
    +++ b/src/bin/pgbench/pgbench.c
    @@ -3563,14 +3563,18 @@ doRetry(CState *st, pg_time_usec_t *now)
     }
     
     /*
    - * Read results and discard it until a sync point.
    + * Read and discard results until the last sync point.
      */
     static int
     discardUntilSync(CState *st)
     {
     	bool		received_sync = false;
     
    -	/* send a sync */
    +	/*
    +	 * Send a sync to ensure at least one PGRES_PIPELINE_SYNC is received
    +	 * and to avoid an infinite loop, since all earlier ones may have
    +	 * already been received.
    +	 */
     	if (!PQpipelineSync(st->con))
     	{
     		pg_log_error("client %d aborted: failed to send a pipeline sync",
    @@ -3578,21 +3582,15 @@ discardUntilSync(CState *st)
     		return 0;
     	}
     
    -	/* receive PGRES_PIPELINE_SYNC and null following it */
    +	/* receive the last PGRES_PIPELINE_SYNC and null following it */
     	for (;;)
     	{
     		PGresult   *res = PQgetResult(st->con);
     
     		if (PQresultStatus(res) == PGRES_PIPELINE_SYNC)
     			received_sync = true;
    -		else if (received_sync)
    +		else if (received_sync && res == NULL)
     		{
    -			/*
    -			 * PGRES_PIPELINE_SYNC must be followed by another
    -			 * PGRES_PIPELINE_SYNC or NULL; otherwise, assert failure.
    -			 */
    -			Assert(res == NULL);
    -
     			/*
     			 * Reset ongoing sync count to 0 since all PGRES_PIPELINE_SYNC
     			 * results have been discarded.
    @@ -3601,6 +3599,23 @@ discardUntilSync(CState *st)
     			PQclear(res);
     			break;
     		}
    +		else
    +		{
    +			if (PQstatus(st->con) == CONNECTION_BAD)
    +			{
    +				pg_log_error("client %d aborted: the backend died while rolling back the failed transaction after",
    +							 st->id);
    +				PQclear(res);
    +				return 0;
    +			}
    +
    +			/*
    +			 * If a PGRES_PIPELINE_SYNC is followed by something other than
    +			 * PGRES_PIPELINE_SYNC or NULL, another PGRES_PIPELINE_SYNC will
    +			 * eventually follow.
    +			 */
    +			received_sync = false;
    +		}
     		PQclear(res);
     	}
     
    -- 
    2.43.0
    
    
    --Multipart=_Wed__12_Nov_2025_18_34_17_+0900_NYrroN9LuyAX4q7A--