| From: | Manu <manuelreyesbravo(at)gmail(dot)com> |
|---|---|
| To: | Hannu Krosing <hannuk(at)google(dot)com> |
| Cc: | pgsql-hackers(at)lists(dot)postgresql(dot)org |
| Subject: | Re: [PATCH] Extensible ReadyForQuery wire protocol message and C hook, for connection pools and WAIT FOR LSN |
| Date: | 2026-10-17 20:39:00 |
| Message-ID: | 179226954033.1033182.6926602894967135011@gmail.com |
| Views: | Whole Thread | Raw Message | Download mbox | Resend email |
| Thread: | |
| Lists: | pgsql-hackers |
Hi Hannu,
> Measuring the indicators against SQL in the same session, four edge cases
> still report a state that does not match the catalog.
I went back to this with sanitizers, a session generator with a catalog
oracle, and a protocol fuzzer, all on v3 over master 26bd08fb5c. A few things
worth flagging; the four v3 cases are only used here as controls.
Indicator desyncs -- the class is larger than those four. Over 24,000 random
sessions (246,368 oracle checks) the generator found five more mechanisms.
Three are false negatives with a live temporary table (T=0), which a pool
would read as a clean session; two need only one connection:
- CREATE TEMP TABLE t; BEGIN; DROP TABLE t; ROLLBACK -> T=0, but t is back.
- CREATE TEMP TABLE t; BEGIN; DISCARD TEMP; ROLLBACK -> T=0, t is back.
- a SERIALIZABLE COMMIT that drops a temp table and then fails with 40001
-> T=0, the table survives (two sessions).
The ROLLBACK/40001 restore and DISCARD-in-a-block are master's behaviour; what
the patch adds is the indicator not reflecting it. Two more are about what T
counts: a temp type or function created through pg_temp_N (not the pg_temp
alias) leaves T=0, and DROP SCHEMA pg_temp_N CASCADE leaves T=1 with nothing
there. The doc says "temporary tables" while the code counts more kinds of
temp object, so that one depends on which definition you intend. P and l had
no mismatches in the whole run.
ready_for_query_hook, error path: a hook that raises ERROR puts the backend
into a loop that sends ErrorResponse without stopping (about a million in two
seconds here), stays at 100% CPU after the client disconnects, and does not
respond to pg_terminate_backend() or "pg_ctl stop -m fast" -- only SIGKILL
ends it. Might be worth saying in the hook's contract that it must not throw,
or wrapping the call so a thrown error can't recurse through ReadyForQuery.
Compatibility: plain is transparent for libpq 14..master. rich at connect
fails cleanly ("message contents do not agree with length in message type
Z"). But turning rich on mid-session, by SET or by reload, hangs every
unpatched libpq I tried (7 of 7, 14 through master) -- so enabling it on a
connection an old client is already using is not safe. Also, patched libpq
drops the connection once a rich 'Z' is longer than 30,000 bytes (master's
long-message guard doesn't list 'Z'), so a hook with a large payload can trip
that.
Memory: the server was clean under ASan+UBSan across make check,
installcheck-parallel with every session in rich plus a hook on each
ReadyForQuery, the TAP suites, and the 24,000 generator sessions. One
client-side report: PQtrace reads past libpq's input buffer on a malformed
rich 'Z' (fe-trace.c), but master's tracer has the same over-read for a
DataRow, so it's a new instance of an existing pattern rather than something
new to the design.
Happy to share the generator, the minimal repros and the hook test module.
Regards,
Manu
| From | Date | Subject | |
|---|---|---|---|
| Next Message | Tom Lane | 2026-10-17 22:51:44 | Re: query_int wrongly parses zero-padded input |
| Previous Message | Raja Sai pranav | 2026-10-17 20:31:11 | Re: Possible race condition in pg_basebackup |