feat: add TRANSACTION_TIMEOUT logical deadline - #980
Conversation
Capture the duration on the logical owner, start the single budget at the first real database RPC including constructor BeginTransaction, preserve it across physical reconstruction, and cancel in-flight RPCs without waiting for the transaction mutex. Pending SET LOCAL may select the duration before activation; session SET after BEGIN applies to a later owner. Restore LOCAL undo at the serialized session safe point. Co-authored-by: apstndb <apstndb@users.noreply.github.com>
…meout-482-a7a6 Co-authored-by: apstndb <apstndb@users.noreply.github.com>
RESET after BEGIN restores the session snapshot without changing the logical owner's captured duration. Document SET/RESET the same way. Co-authored-by: apstndb <apstndb@users.noreply.github.com>
Co-authored-by: apstndb <apstndb@users.noreply.github.com>
Code Metrics Report📊 View detailed coverage report (available for 7 days)
Details | | main (c7ed015) | #980 (97dfd5c) | +/- |
|---------------------|----------------|----------------|-------|
+ | Coverage | 86.6% | 86.7% | +0.1% |
| Files | 113 | 115 | +2 |
| Lines | 10715 | 10951 | +236 |
+ | Covered | 9280 | 9499 | +219 |
+ | Code to Test Ratio | 1:2.3 | 1:2.3 | +0.0 |
| Code | 23964 | 24397 | +433 |
+ | Test | 55774 | 57869 | +2095 |
- | Test Execution Time | 1m44s | 2m11s | +27s |Code coverage of files in pull request scope (88.7% → 89.1%, patch 89.8%)
Reported by octocov |
…meout-482-a7a6 # Conflicts: # docs/system_variables.md # internal/mycli/heartbeat_owner_test.go # internal/mycli/system_variables.go Co-authored-by: apstndb <apstndb@users.noreply.github.com>
|
Reviewed HEAD
The independent probes failed with those exact causes on both The required pre-push gate also remains unmet: the receipt says |
|
Additional blocking finding on the same reviewed HEAD [P1] Make expiry retirement and the statement-entry restoration boundary atomic. I reproduced this deterministically with an overlay hook immediately after the new entry drain, using the existing expiry callback before the actual Please implement an atomic handoff under the lifecycle synchronization so an expired owner's undo is restored before another statement reads defaults or installs a new owner. Registry setters must remain outside timer goroutines, and an unsynchronized/standalone execution flag or another one-shot drain would leave the same race. Add this exact ordering regression alongside expiry-before-entry and in-flight cancellation cases. Location: entry restoration, timer retirement. Keep the same additive PR and the previously requested full |
Bind remaining TRANSACTION_TIMEOUT at every BatchUpdate RPC, freeze the selected duration after first real database use even when NULL/0, and restore expired SET LOCAL undo before a later statement reads defaults or installs a new owner. Co-authored-by: apstndb <apstndb@users.noreply.github.com>
…meout-482-a7a6 # Conflicts: # docs/system_variables.md Co-authored-by: apstndb <apstndb@users.noreply.github.com>
Keep expiry retirement and owner-install restoration atomic under tm.mu. Do not hold a second lifecycle mutex for the whole statement, which deadlocked Session.Close while Batch DML was in flight. Co-authored-by: apstndb <apstndb@users.noreply.github.com>
|
Review update for exact HEAD The independent actual-RPC Batch DML deadline probes and NULL/0 first-use rejection now pass. The original timeout/verbose owner-install regression also passes. Thank you for keeping the published history additive. [P1] The expiry/LOCAL restoration boundary is still incomplete. I reproduced both remaining cases with the new
These are deterministic forced-interleaving reproductions on this HEAD, not elapsed-time claims. Please fix the shared statement/retirement protocol, cover ordinary SET plus frozen priority/isolation and statement-default reads, and retain constructor/in-flight cancellation and nested execution coverage. Do not hold a non-reentrant statement mutex across an RPC or move Registry.Set into timer callbacks. A synchronized, owner-aware deferred-retirement protocol is one possible design; choose the smallest protocol with a clear ordering argument. Moving two default reads alone leaves the successful SET regression. Validation remains full |
Expire during ExecuteStatement marks the matching owner pending instead of detaching SET LOCAL undo, then restores at the shared barrier before ordinary SET, frozen priority/isolation, statement-timeout defaults, and replacement BEGIN. Timers still cancel in-flight RPCs and never call Registry.Set. Co-authored-by: apstndb <apstndb@users.noreply.github.com>
|
Review update for exact HEAD All earlier independent probes now pass, including the actual Batch DML deadlines, NULL/0 freeze, expiry before BEGIN with LOCAL priority, and ordinary session SET preservation. The reported uncached full/Docker gate receipt also resolves the earlier unit-only uncertainty. [P2] Close the final statement-depth/expiry handoff atomically. I reproduced this on this HEAD with one test-only overlay callback immediately after the final Please make the final frame-depth transition and decision to retire an expired matching owner a single tm.mu critical section, then restore detached registry entries outside the lock. Preserve nested-frame semantics and the rule that timer callbacks do not touch the registry. The invariant at that boundary should rule out depth0 with an already-processed expiry still pending and no watcher left to retire it. Add the exact final-frame interleaving regression; another unsynchronized one-shot drain alone simply moves this gap. Location: leaveStatement. This is a small completion of the new protocol; keep it additive and run full make check plus make check-race before pushing. No merge or history rewrite by the worker. |
leaveStatement now decrements statement depth and retires an expire-pending owner in one tm.mu section, then restores detached SET LOCAL values outside the lock. A timeout callback can no longer leave depth 0 with expirePending set and no watcher. Nested frames still only decrement. Co-authored-by: apstndb <apstndb@users.noreply.github.com>
|
Independent re-review of exact HEAD The earlier findings are resolved additively: On this exact HEAD, my independent fake-gRPC/deadline/forced-interleaving probes and the timeout test suite pass, including every previously failing reproduction. Independent full This acceptance concerns the logical read/write timeout and its integration; it does not add user-idle expiry or automatic ABORTED retry, and local fake/emulator tests are not a claim of managed-service validation. |
Summary
Implements
TRANSACTION_TIMEOUTas a logical read/write deadline for #482.NULL;NULL/0 means no additional transaction deadline.SET LOCALmay select it before the first real database RPC; changing it after the budget starts is rejected. SessionSETorRESETafterBEGINapplies to a later owner.BeginTransactionon pinned Go Spanner v1.95.0ReadWriteStmtBasedTransaction. Client-onlyBEGIN/SHOWand buffering automatic DML do not start it.STATEMENT_TIMEOUTdeadlines.SET LOCALat the serialized session safe point (start/end ofExecuteStatement, andClose). Timer goroutines never callRegistry.Set.Does not change automatic-DML queue/flush signatures owned by #979/#401.
Fixes #482
Test plan
go test -short ./...,golangci-lint run,make fmt-check(exit 0)make check-race(exit 0)go test -short -coverpkg=./internal/mycli ./internal/myclicoverage 82.6% (floor 80%)make test/ emulator (this VM has no Docker; localmake checkfailed only on integration container startup)