Skip to content

fix(cluster): GCS block-ship race trio — dedup swallow on retryable deny, invalidate-slot instant fail, duplicate-reply overwrite - #43

Merged
sqlrush merged 1 commit into
mainfrom
fix/gcs-block-ship-races
Jul 12, 2026
Merged

fix(cluster): GCS block-ship race trio — dedup swallow on retryable deny, invalidate-slot instant fail, duplicate-reply overwrite#43
sqlrush merged 1 commit into
mainfrom
fix/gcs-block-ship-races

Conversation

@sqlrush

@sqlrush sqlrush commented Jul 12, 2026

Copy link
Copy Markdown
Owner

Summary

Three functional defects in the GCS block plane surfaced by the 4-node S3 bench, each reproducible at low concurrency and each mapping to a distinct S3 error signature:

  1. Dedup swallow on retryable deny — a retryable master denial (DENIED_PENDING_X reader guard, the e2 S->X nudge deny, direct-land forward denies) never released its IN_FLIGHT dedup entry, so the requester's same-key convergence retry was silently swallowed until the TTL sweep. Each swallowed round burned a full cluster.gcs_reply_timeout_ms (the bench's dominant 53R90 retransmit-exhaustion class and its ~26s/52s latency walls). Fixed with cluster_gcs_block_dedup_remove before every such deny (6 sites).
  2. Invalidate-slot instant fail — the node-wide invalidate broadcast slot failed a busy claim instantly, so two concurrent local S->X upgrades on one node (even on unrelated blocks) surfaced the loser as a spurious S->X upgrade invalidate did not complete ERROR. The blocking variant's callers are all backends, so the claim now waits bounded by the ACK budget on the broadcast CV; the release broadcasts the CV.
  3. Duplicate-reply overwrite — a duplicate GCS_BLOCK_REPLY (dedup CACHED_REPLY resend racing the original) overwrote a received-but-unconsumed outstanding slot while the requester consumed the 8KB image lock-free -> torn CRC32C -> false DENIED_CHECKSUM_FAIL ("wire-ABI drift" on loopback). Every delivery path now drops the duplicate once reply_received is set (first-reply-wins).

Test plan

  • TDD red->green: new t/390 (3-node) reproduces all three pre-fix — exactly 4 assertions red (organic PENDING_X legs stuck 5.15s each, injected leg 5.14s, second concurrent upgrade fails with the exact S3 error string, duplicate silently accepted) — and passes clean post-fix
  • cluster_unit 175/175 (clean rebuild; new dedup U10 locks remove-reopens-entry)
  • cluster_regress 13/13
  • PG 219/219
  • TAP band: t/015 017 020 023 030 111 112 113 114 348 366 390 all PASS (injection registry 169->170 baselines refreshed)
  • check-format 0 violations
  • fast-gate 5 jobs green (this PR)
  • 4-node S3 rerun on the merged tree

Spec: spec-2.34-gcs-block-reliability-hardening.md
Spec: spec-6.12-crossnode-cache-fusion-perf-optimization.md

…eny, invalidate-slot instant fail, duplicate-reply overwrite

The 4-node S3 bench surfaced three functional defects in the GCS block
plane, all reproducible at low concurrency:

1. A retryable master denial (DENIED_PENDING_X reader guard, the e2
   S->X nudge deny, and the direct-land forward denies) replied after
   dedup registration but never released the IN_FLIGHT entry.  The
   requester's convergence retry reuses the same (request_id, epoch)
   dedup key, so the retry was silently swallowed as
   IN_FLIGHT_DUPLICATE until the TTL sweep — each swallowed round burned
   a full cluster.gcs_reply_timeout_ms (observed: the bench's dominant
   53R90 retransmit-exhaustion class and its ~26s/52s latency walls).
   Fix: cluster_gcs_block_dedup_remove before every such deny (6 sites).

2. The node-wide invalidate broadcast slot failed a busy claim
   INSTANTLY inside gcs_block_broadcast_invalidate_and_wait_ext, so two
   concurrent local S->X upgrades on one node — even on unrelated
   blocks — surfaced the loser as a spurious "S->X upgrade invalidate
   did not complete" ERROR.  Every caller of the blocking variant is a
   backend (dispatch paths use the nowait fan-out), so the claim now
   waits bounded by the ACK budget on the broadcast CV; the slot
   release broadcasts the CV to wake claim waiters.

3. Reply delivery overwrote a received-but-unconsumed outstanding slot
   on duplicate replies (dedup CACHED_REPLY resend racing the original)
   while the requester consumed the 8KB image lock-free -> torn CRC32C
   -> false DENIED_CHECKSUM_FAIL ("wire-ABI drift" on loopback).  Fix:
   first-reply-wins — every delivery path (wire handler, direct-land
   completion, direct fail-slot) drops the duplicate once
   reply_received is set (stale_reply_drop_count++), making the slot
   reply fields immutable from reply_received=true until the owner
   rearms them.

TDD: new t/390 (3-node) reproduces all three pre-fix — 5.15s
swallowed-retry walls on the organic and injected PENDING_X legs, the
exact "invalidate did not complete" collision error, and the silent
duplicate overwrite — and goes green with the fixes.  New injection
point cluster-gcs-block-duplicate-grant-reply (registry 169 -> 170,
baselines refreshed); dedup unit U10 locks the remove-reopens-entry
contract.

Spec: spec-2.34-gcs-block-reliability-hardening.md
Spec: spec-6.12-crossnode-cache-fusion-perf-optimization.md
@sqlrush
sqlrush merged commit c193455 into main Jul 12, 2026
5 checks passed
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