Skip to content

Stage 3: reset acking + isolation carrier (ADO #47339) - #301

Closed
Saurabh Singh (saurabh500) wants to merge 1 commit into
saurabh500-stage-2-odbc-pooling-primitivesfrom
saurabh500-stage-3-reset-acking-isolation
Closed

Stage 3: reset acking + isolation carrier (ADO #47339)#301
Saurabh Singh (saurabh500) wants to merge 1 commit into
saurabh500-stage-2-odbc-pooling-primitivesfrom
saurabh500-stage-3-reset-acking-isolation

Conversation

@saurabh500

@saurabh500 Saurabh Singh (saurabh500) commented Aug 15, 2026

Copy link
Copy Markdown
Contributor

Summary

Stage 3 of the mssql-odbc connection pooling effort (ADO User Story #47317, Task [AB#47339](https://sqlclientdrivers.visualstudio.com/b95cf060-8083-439d-8ef1-405d5bf219d8/_workitems/edit/47339)). Makes the connection reset self-acking at pool checkout so a borrower never inherits a session whose reset has not yet been processed, and confirms the isolation/autocommit checkout lifecycle carries and survives the reset.

Stacked on Stage 2 PR #296 (→ #294#293). Base branch: saurabh500-stage-2-odbc-pooling-primitives, not main.

A2 — reset is self-acking (mssql-tds)

  • New TdsClient::reset_connection(): arms the full RESETCONNECTION bit and drives a minimal SELECT 1 round trip so the server processes the reset and returns its ResetConnection ENVCHANGE within the call. The ack flows through Stage 1's on_reset_connection_ack(), clearing session-bound caches before checkout. A failed round trip returns an error so the caller can discard the connection.
  • prepare_reset_connection(bool) is unchanged (the deferred-piggyback path); reset_connection() is the eager variant.
  • New TdsClient::mark_connection_dead() lets the ODBC layer deterministically poison a client whose reset failed.
  • Unit test proves the round trip carries the RESETCONNECTION bit and the ack clears session-bound caches.

B4 — wire eager reset + isolation carrier (mssql-odbc)

  • SQLSetConnectAttr(SQL_ATTR_RESET_CONNECTION) now calls reset_connection() after arming, so the reset is processed+acked before the set-attr returns. The DBC mutex is never held across the round-trip I/O (claim → drop lock → I/O → restore). On failure it poisons the client and surfaces 08S01 so mssql-python discards it at checkout.
  • Confirmed the SQL_ATTR_TXN_ISOLATION handler still emits a real SET TRANSACTION ISOLATION LEVEL batch; because the reset now acks eagerly, a later short-circuited isolation SET can't leave the reset unacknowledged. Test covers a borrower raising isolation to SERIALIZABLE, resetting, then re-applying READ COMMITTED at checkout.
  • Documented the D9 raw-T-SQL isolation caveat (stale cache → possible leak; shared, documented limitation, not fixed here) as a code comment at the same-value short-circuit.

B5 — autocommit / EndTran lifecycle confirmation

  • Added a checkout-cycle test: acquire (reset, eagerly acked) → setautocommit(False) (begin-txn) → check-in → next acquire (reset) reuses the same physical connection and leaves it reusable. No autocommit/EndTran plumbing rebuilt.

Tests

  • New/updated unit + mock tests in mssql-tds and mssql-odbc: eager-ack round trip, failure poison → 08S01, reset+isolation re-apply, and the full checkout lifecycle. Extended test_client_support with a ResetConnection ENVCHANGE token helper and mark_known_dead support on the replay transport.

Validation

  • cargo bfmt ✅ (workspace + mssql-py-core)
  • cargo bclippy ✅ (warnings-as-errors, clean)
  • mssql-tds / mssql-odbc lib unit tests ✅ — the only failures are the pre-existing cert/TLS-fixture tests on the base, unrelated to this change.

References [AB#47339](https://sqlclientdrivers.visualstudio.com/b95cf060-8083-439d-8ef1-405d5bf219d8/_workitems/edit/47339).

Drive the RESETCONNECTION round trip eagerly inside
SQLSetConnectAttr(SQL_ATTR_RESET_CONNECTION) so the reset is processed
and acknowledged before pool checkout returns, rather than riding a later
request that may short-circuit. A failed reset poisons the client and
surfaces 08S01 so mssql-python discards the connection.

Add TdsClient::reset_connection() (arms the bit and forces the ack round
trip) and mark_connection_dead(); wire the ODBC handler to them, map
failures to 08S01, and document the D9 raw-T-SQL isolation caveat at the
same-value short-circuit. Cover the eager ack, poison, reset+isolation
re-apply, and full checkout-cycle lifecycle with unit/mock tests.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 63e24621-7665-4572-a5b8-e5dfa55060a0
@saurabh500

Copy link
Copy Markdown
Contributor Author

Consolidated into #308, which contains all of this work in a single PR against main. Closing in favor of #308.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area:connectionpool Work done for connection pool enhancement New feature or request

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant