On Wed, Jul 15, 2020 at 12:18 AM Andres Freund <and...@anarazel.de> wrote:

> Hi,
>
> On 2020-07-10 19:01:49 -0400, Alvaro Herrera wrote:
> > Totally unasked for, here's a rebase of this patch series.  I didn't do
> > anything other than rebasing to current master, solving a couple of very
> > trivial conflicts, fixing some whitespace complaints by git apply, and
> > running tests to verify everthing works.
> >
> > I don't foresee working on this at all, so if anyone is interested in
> > seeing this feature in, I encourage them to read and address
> > Horiguchi-san's feedback.
>
> Nor am I planning to do so, but I do think its a pretty important
> improvement.
>
>
>
> > +/*
> > + * PQrecyclePipelinedCommand
> > + *   Push a command queue entry onto the freelist. It must be a
> dangling entry
> > + *   with null next pointer and not referenced by any other entry's
> next pointer.
> > + */
>
> Dangling sounds a bit like it's already freed.
>
>
>
> > +/*
> > + * PQbatchSendQueue
> > + *   End a batch submission by sending a protocol sync. The connection
> will
> > + *   remain in batch mode and unavailable for new synchronous command
> execution
> > + *   functions until all results from the batch are processed by the
> client.
>
> I feel like the reference to the protocol sync is a bit too low level
> for an external API. It should first document what the function does
> from a user's POV.
>
> I think it'd also be good to document whether / whether not queries can
> already have been sent before PQbatchSendQueue is called or not.
>
>
> > +/*
> > + * PQbatchProcessQueue
> > + *    In batch mode, start processing the next query in the queue.
> > + *
> > + * Returns 1 if the next query was popped from the queue and can
> > + * be processed by PQconsumeInput, PQgetResult, etc.
> > + *
> > + * Returns 0 if the current query isn't done yet, the connection
> > + * is not in a batch, or there are no more queries to process.
> > + */
> > +int
> > +PQbatchProcessQueue(PGconn *conn)
> > +{
> > +     PGcommandQueueEntry *next_query;
> > +
> > +     if (!conn)
> > +             return 0;
> > +
> > +     if (conn->batch_status == PQBATCH_MODE_OFF)
> > +             return 0;
> > +
> > +     switch (conn->asyncStatus)
> > +     {
> > +             case PGASYNC_COPY_IN:
> > +             case PGASYNC_COPY_OUT:
> > +             case PGASYNC_COPY_BOTH:
> > +                     printfPQExpBuffer(&conn->errorMessage,
> > +                                libpq_gettext_noop("internal error,
> COPY in batch mode"));
> > +                     break;
>
> Shouldn't there be a return 0 here?
>
>
>
> > +     if (conn->batch_status == PQBATCH_MODE_ABORTED && conn->queryclass
> != PGQUERY_SYNC)
> > +     {
> > +             /*
> > +              * In an aborted batch we don't get anything from the
> server for each
> > +              * result; we're just discarding input until we get to the
> next sync
> > +              * from the server. The client needs to know its queries
> got aborted
> > +              * so we create a fake PGresult to return immediately from
> > +              * PQgetResult.
> > +              */
> > +             conn->result = PQmakeEmptyPGresult(conn,
> > +
>         PGRES_BATCH_ABORTED);
> > +             if (!conn->result)
> > +             {
> > +                     printfPQExpBuffer(&conn->errorMessage,
> > +
>  libpq_gettext("out of memory"));
> > +                     pqSaveErrorResult(conn);
> > +                     return 0;
>
> Is there any way an application can recover at this point? ISTM we'd be
> stuck in the previous asyncStatus, no?
>
>
> > +/* pqBatchFlush
> > + * In batch mode, data will be flushed only when the out buffer reaches
> the threshold value.
> > + * In non-batch mode, data will be flushed all the time.
> > + */
> > +static int
> > +pqBatchFlush(PGconn *conn)
> > +{
> > +     if ((conn->batch_status == PQBATCH_MODE_OFF)||(conn->outCount >=
> OUTBUFFER_THRESHOLD))
> > +             return(pqFlush(conn));
> > +     return 0; /* Just to keep compiler quiet */
> > +}
>
> unnecessarily long line.
>
>
> > +/*
> > + * Connection's outbuffer threshold is set to 64k as it is safe
> > + * in Windows as per comments in pqSendSome() API.
> > + */
> > +#define OUTBUFFER_THRESHOLD  65536
>
> I don't think the comment explains much. It's fine to send more than 64k
> with pqSendSome(), they'll just be send with separate pgsecure_write()
> invocations. And only on windows.
>
> It clearly makes sense to start sending out data at a certain
> granularity to avoid needing unnecessary amounts of memory, and to make
> more efficient use of latency / serer side compute.
>
> It's not implausible that 64k is the right amount for that, I just don't
> think the explanation above is good.
>
> > diff --git a/src/test/modules/test_libpq/testlibpqbatch.c
> b/src/test/modules/test_libpq/testlibpqbatch.c
> > new file mode 100644
> > index 0000000000..4d6ba266e5
> > --- /dev/null
> > +++ b/src/test/modules/test_libpq/testlibpqbatch.c
> > @@ -0,0 +1,1456 @@
> > +/*
> > + * src/test/modules/test_libpq/testlibpqbatch.c
> > + *
> > + *
> > + * testlibpqbatch.c
> > + *           Test of batch execution functionality
> > + */
> > +
> > +#ifdef WIN32
> > +#include <windows.h>
> > +#endif
>
> ISTM that this shouldn't be needed in a test program like this?
> Shouldn't libpq abstract all of this away?
>
>
> > +static void
> > +simple_batch(PGconn *conn)
> > +{
>
> ISTM that all or at least several of these should include tests of
> transactional behaviour with pipelining (e.g. using both implicit and
> explicit transactions inside a single batch, using transactions across
> batches, multiple explicit transactions inside a batch).
>
>
>
> > +     PGresult   *res = NULL;
> > +     const char *dummy_params[1] = {"1"};
> > +     Oid                     dummy_param_oids[1] = {INT4OID};
> > +
> > +     fprintf(stderr, "simple batch... ");
> > +     fflush(stderr);
>
> Why do we need fflush()? IMO that shouldn't be needed in a use like
> this? Especially not on stderr, which ought to be unbuffered?
>
>
> > +     /*
> > +      * Enter batch mode and dispatch a set of operations, which we'll
> then
> > +      * process the results of as they come in.
> > +      *
> > +      * For a simple case we should be able to do this without interim
> > +      * processing of results since our out buffer will give us enough
> slush to
> > +      * work with and we won't block on sending. So blocking mode is
> fine.
> > +      */
> > +     if (PQisnonblocking(conn))
> > +     {
> > +             fprintf(stderr, "Expected blocking connection mode\n");
> > +             goto fail;
> > +     }
>
> Perhaps worth adding a helper for this?
>
> #define EXPECT(condition, explanation) \
> ...
> or such?
>
> Greetings,
>
> Andres Freund
>
>
>
The build is failing for this patch, can you please take a look at this?

https://cirrus-ci.com/task/4568547922804736
https://ci.appveyor.com/project/postgresql-cfbot/postgresql/build/1.0.129221


I am marking the patch "Waiting on Author"

-- 
Ibrar Ahmed

Reply via email to