libpq: Process buffered SSL read bytes to support records >8kB on async API

Lars Kanis <lars@greiz-reinsdorf.de>

From: Lars Kanis <lars@greiz-reinsdorf.de>
To: pgsql-hackers@lists.postgresql.org
Date: 2024-09-08T20:07:53Z
Lists: pgsql-hackers

Commits

Same data as JSON: GET /api/v1/messages/:b64id/commits the thread's linked commits as JSON, with link sources. API reference →
  1. Remove incorrect Assert.

Attachments

Dear hackers,

I'm the maintainer of ruby-pg the ruby interface to the PostgreSQL 
database. This binding uses the asynchronous API of libpq by default to 
facilitate the ruby IO wait and scheduling mechanisms.

This works well with the vanilla postgresql server, but it leads to 
starvation with other types of servers using the postgresql wire 
protocol 3. This is because the current functioning of the libpq async 
interface depends on a maximum size of SSL records of 8kB.

The following servers were reported to starve with ruby-pg:

* AWS RDS Aurora Serverless [1]
* YugabyteDb [2]
* CockroachDB [3]

They block infinitely on certain message sizes sent from the backend to 
the libpq frontend. It is best described in [4]. A repro docker 
composition is provided by YugabyteDB at [2].

To fix this issue the attached patch calls pqReadData() repeatedly in 
PQconsumeInput() until there is no buffered SSL data left to be read. 
Another solution could be to process buffered SSL read bytes in 
PQisBusy() instead of PQconsumeInput() .

The synchronous libpq API isn't affected, since it supports arbitrary 
SSL record sizes already. That's why I think that the asynchronous API 
should also support bigger SSL record sizes.

Regards, Lars


[1] https://github.com/ged/ruby-pg/issues/325
[2] https://github.com/ged/ruby-pg/issues/588
[3] https://github.com/ged/ruby-pg/issues/583
[4] https://github.com/ged/ruby-pg/issues/325#issuecomment-737561270