Skip to content

Add CancelAndDrainContextWatcherHandler#2537

Open
sean- wants to merge 1 commit into
jackc:masterfrom
sean-:gh-2534
Open

Add CancelAndDrainContextWatcherHandler#2537
sean- wants to merge 1 commit into
jackc:masterfrom
sean-:gh-2534

Conversation

@sean-
Copy link
Copy Markdown
Contributor

@sean- sean- commented Apr 17, 2026

Replace the racy 100ms sleep added in 93a5797 with a deterministic single-";" drain that absorbs any pending SQLSTATE 57014 (query_canceled) before the connection is reused.

Key changes:

  • Add CancelAndDrainContextWatcherHandler implementing ctxwatch.Handler. HandleUnwatchAfterCancel sends exactly one ";" after a successful cancel: sufficient because PostgreSQL's QueryCancelPending is a single flag, not a queue.

  • Add mutex-guarded three-state cancel machine (idle/inFlight/sent) on CancelRequest. This prevents double-send from concurrent callers (ctxwatch, asyncClose, direct user code) which would produce multiple 57014 responses that a single drain cannot reconcile.

  • Fix data race on pid and secretKey in CancelRequest by grouping both into a backendKeyData struct behind atomic.Pointer.

  • Extract cancel protocol constants (cancelRequestCode, negotiateSSLCode, packet field offsets) from magic numbers, referencing CancelRequestPacket in src/include/libpq/pqcomm.h.

AI disclosure

Per the contributing guidelines: Claude Code (Anthropic, Opus 4.6) was used for drafting and code generation. I understand the code, traced the protocol flows through the PostgreSQL source, and can answer questions about the change directly.

Fixes: #2534

Replace the racy 100ms sleep added in 93a5797 with a deterministic
single-";" drain that absorbs any pending SQLSTATE 57014
(query_canceled) before the connection is reused.

Key changes:

- Add CancelAndDrainContextWatcherHandler implementing ctxwatch.Handler.
  HandleUnwatchAfterCancel sends exactly one ";" after a successful
  cancel, sufficient because PostgreSQL's QueryCancelPending is a single
  flag, not a queue.

- Add mutex-guarded three-state cancel machine (idle/inFlight/sent) on
  CancelRequest. This prevents double-send from concurrent callers
  (ctxwatch, asyncClose, direct user code) which would produce multiple
  57014 responses that a single drain cannot reconcile.

- Fix data race on pid and secretKey in CancelRequest by grouping both
  into a backendKeyData struct behind atomic.Pointer.

- Extract cancel protocol constants (cancelRequestCode, negotiateSSLCode,
  packet field offsets) from magic numbers, referencing CancelRequestPacket
  in src/include/libpq/pqcomm.h.

AI: Claude Code (Anthropic) used for drafting and code generation.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant