| From: | Dmitrii Bondar <d(dot)bondar(at)postgrespro(dot)ru> |
|---|---|
| To: | Robert Haas <robertmhaas(at)gmail(dot)com> |
| Cc: | pgsql-hackers(at)lists(dot)postgresql(dot)org |
| Subject: | Re: Pgbench: remove synchronous prepare |
| Date: | 2026-04-28 09:29:51 |
| Message-ID: | 6e161344-d26a-4e3d-aa12-83a05a3ca8dc@postgrespro.ru |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
On 4/27/26 12:01 AM, Robert Haas wrote:
> On Mon, Mar 16, 2026 at 3:46 AM Dmitrii Bondar<d(dot)bondar(at)postgrespro(dot)ru> wrote:
>> Rebase.
> Hi,
>
> I think that this patch is changing more behavior than is explained in
> the commit message. The existing code calls PQsendQueryPrepared, which
> only tries to execute an already-prepared query. The replacement code
> tries to prepare the query. It is not clear to me what's going on
> here. I would have expected that we would only ever reach that point
> in the code with the query already prepared; otherwise, the existing
> code would presumably fail. But if that is the case then how is the
> new code managing to do anything different than the old code?
>
> Another way to see that the patch must be changing more behavior than
> advertised is the change to 001_pgbench_with_server.pl. That change
> comes with no comment changes and no explanation of any kind.
>
> If this patch were just about doing something asynchronously instead
> of synchronously, I think that would be fine, but I don't think that's
> all that is happening here. The original post explains the problem
> behavior (pgbench freezing under certain circumstances) but I don't
> understand what causes that behavior. I think I would understand
> better if the original complaint were about something other than
> session pooling mode: then, I might expect that we might unexpectedly
> discover that our session does not have something prepared which we
> expected to find prepared, and maybe this revised logic in
> sendCommand() would somehow fix that. But in session pooling mode,
> shouldn't everything be the same as if connection pooling is not in
> use at all? What's actually different?
>
Hi,
The patch does not change the existing behavior when a query has already
been prepared. Both the old and new code paths use
|PQsendQueryPrepared|, which sends a bind-execute-sync packet sequence
without waiting for a response.
The main difference appears when the query has not yet been prepared. In
the old code, |PQprepare| is called, which sends a parse message and
then waits for the result via |PQexecFinish|. Since |PQexecFinish|
blocks until a response arrives, it can block the entire thread if the
server has not responded yet.
I replaced the call to |PQprepare| with a call to the new |PQsendPBES|
function. Like |PQsendQueryPrepared|, it works asynchronously, but it
sends a parse-bind-execute-sync sequence instead. This change avoids
thread blocking because it eliminates the need to call |PQexecFinish|.
I chose to send a parse-bind-execute-sync sequence to match the behavior
of extended query mode, in which pgbench sends the same sequence, but
with an unnamed statement.
The expected output for |001_pgbench_with_server.pl| was changed for the
following reason. In the old pgbench code, |prepareCommand| is called
and receives |ERROR: syntax error|. Since |prepareCommand| does not
return a status, pgbench continues execution and then attempts to run
the command with |PQsendQueryPrepared|. This leads to the error
|prepared statement .* does not exist|, which is caused by the bind packet.
In the new code, |PQsendPBES| sends a parse-bind-execute-sync packet
sequence. If the parse step fails with |ERROR: syntax error|, all
subsequent messages are ignored until the sync packet is processed. That
is why the additional |prepared statement .* does not exist| error from
the bind packet no longer appears.
Session mode is indeed the most transparent way to use a pooler.
However, pgbench can become stuck when the number of clients exceeds the
pool size. If the pooler cannot reserve a backend for a client, it
places the client in a waiting queue. In that case, pgbench may wait
indefinitely because it is blocked in |PQprepare|, and the pgbench
thread cannot process responses for other clients.
Regards,
Dmitrii Bondar
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Richard Guo | 2026-04-28 10:09:06 | Re: Remove inner joins based on foreign keys |
| Previous Message | Yugo Nagata | 2026-04-28 09:14:20 | Re: Infinite Autovacuum loop caused by failing virtual generated column expression |