laserninja commented on PR #12470:
URL: https://github.com/apache/gravitino/pull/12470#issuecomment-5472661180

   Thanks @nevzheng, and no worries about the delay. All four items are 
addressed in `ee89c9f`. Each of the two blocking ones turned out to be a live 
defect rather than only a gap in coverage, and the fourth surfaced a third.
   
   **Case variants (blocking).** Confirmed: `reserve("017F22E2-…")` and 
`reserve("017f22e2-…")` hashed to different entries, so both won `RESERVED` and 
the mutation ran twice — and the spec's own example is upper case, so this was 
reachable by a spec-conformant client. Added `IdempotencyKeys.canonicalize`, 
folding with `Locale.ROOT`, applied at the store boundary rather than trusting 
callers. This also matters for the JDBC store, where `utf8mb4_bin` is 
case-sensitive; only the folded form is ever written.
   
   **Fencing (blocking).** Confirmed, and worse on the release path than the 
finalize path. `release()` deleted whatever record it found, so a caller whose 
reservation had been evicted freed the *current* owner's key and let a third 
request execute the mutation a second time. `reserve` now takes a caller-minted 
claim that `finalizeRecord` and `release` must present; a mismatched claim is a 
no-op. The manager mints one per attempt.
   
   **Every concurrent result (non-blocking).** Now collects all 16 outcomes and 
asserts 1 `RESERVED`, 15 `DUPLICATE`, and no thrown exception, instead of 
counting winners only.
   
   **Controllable clock (non-blocking).** This one exposed the third bug: 
`asMap().computeIfPresent` counts as a write under `expireAfterWrite`, so 
finalizing restarted the timer and a record finalized at T+29m survived to 
T+59m — past the lifetime advertised to clients. Rather than only testing it, 
expiry now derives from each record's own `expiresAtMs`: `reserve` treats a 
record past its deadline as absent, `load` filters it, and Caffeine's expiry is 
demoted to memory reclamation. Behavior no longer depends on when cache 
maintenance runs, and it matches how a database-backed store will compare 
`expires_at`. The store takes an injected clock for tests.
   
   One test changed premise as a result: 
`testPurgeExpiredRemovesOnlyElapsedRecords` used to reserve an already-expired 
record, which now never enters the cache at all, so it runs on the injected 
clock instead.
   
   `iceberg-common` is 101 tests green, and #12474 is rebased on this with the 
manager updated for the new signatures (`iceberg-rest-server`, 419 tests green).
   
   One follow-up worth flagging: this SPI change reaches the Phase 2 JDBC 
store, which was written against the old three-argument `reserve`/`release`. 
That work needs the claim plumbed through its schema too — a `claim` column on 
`iceberg_idempotency_key_meta` and `AND claim = ?` on the finalize and release 
statements — otherwise the JDBC store would silently lose the fencing guarantee 
this review added.
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to