Skip to content

fix: stop a connection from keeping every cursor it created - #1052

Open
vuanhphung wants to merge 1 commit into
mainfrom
perf/rd-py-overhead-2
Open

vuanhphung wants to merge 1 commit into
mainfrom
perf/rd-py-overhead-2

Conversation

@vuanhphung

@vuanhphung vuanhphung commented Nov 13, 2026 •

Copy link
Copy Markdown
Collaborator

What type of PR is this?

  • Bug Fix

Description

Connection appended every cursor it created to _cursors and never removed it, so a long-lived connection kept one closed cursor per query: 248 bytes each, about 50 MB after 200,000 queries, and connection.close() then took 42 ms to walk them. Connections that run queries back to back for a long time (pools, services) grow without bound.

Cursor.close() now drops its entry, and _cursors is a dict used as an ordered set so that removal is O(1). Connection.close() still closes every cursor that is open (and its active result set), iterating over a copy. The change is in Connection/Cursor, so it applies to the Thrift, SEA and kernel backends alike.

How is this tested?

  • Unit tests
  • Manually

A unit test for the Thrift and kernel backends checks that closed cursors leave _cursors, that closing twice is fine, and that connection.close() still closes the open cursors and their result sets; it fails on main. Full unit suite passes.

One kernel connection to a local mock server, 200,000 cursor()/close() cycles (tracemalloc):

main this PR
memory retained 49.6 MB (248 B per cursor) 0
connection.close() 41.6 ms 1.4 ms

Throughput is unchanged: 200 threads x 30 s against the mock (20 ms server time, client and mock pinned to separate cores), 3 interleaved runs: 1336 / 1411 / 1411 QPS on main vs 1374 / 1337 / 1440 with this PR.

Live benchmark (staging Large Reyden warehouse)

TPC-H Q6 on a Large Real-Time warehouse, 800 sessions (4 processes x 200 threads), cold start, each session querying back to back for 120 s, 16 client cores. Isolated A/B: only this change vs connector main 0c1b9e8 + kernel 1.4.0, 3 interleaved rounds, nothing else on the warehouse. Measured at bec22d8. Median (min-max):

main this PR
Average QPS (setup included) 2050 (1957-2114) 2098 (2056-2114)
Steady QPS (after all sessions open) 2084 (1992-2149) 2135 (2094-2150)
Query latency p50 (ms) 368 (357-378) 359 (356-365)
Client CPU per query (ms) 1.24 (1.19-1.26) 1.23 (1.19-1.27)
Peak RSS per process (MB) 383 (382-383) 364 (363-369)

QPS within noise; memory drops because closed cursors are no longer retained (the gap grows with session length).

SELECT 1 on an X-Large Real-Time warehouse (driver-bound). Q6 above is limited by the warehouse, so the same harness also ran SELECT 1, where the client is the limit: X-Large warehouse, 4 processes x 200 threads, 120 s, 16 client cores, this change vs connector main 0c1b9e8 + kernel 1.4.0, measured at bec22d8, run in rotation with the other factory PRs, 2 rounds. Median (min-max):

main this PR
Average QPS (setup included) 6094 (6040-6147) 6057 (6025-6088)
Peak QPS (best second) 6513 (6503-6523) 6544 (6510-6578)
Query latency p50 (ms) 124 (123-124) 124 (124-124)
Client CPU per query (ms) 1.34 (1.33-1.35) 1.33 (1.33-1.34)

Average QPS change per round: -0.2%, -1.0%.

Related Tickets & Documents

This pull request and its description were written by Isaac.

Connection._cursors held every cursor ever created, so a long-lived
connection grew by one closed cursor per query and close() walked all
of them. Cursor.close() now removes its entry; Connection.close() still
closes every cursor that is open.

Signed-off-by: Vu Anh Phung <[email protected]>
Co-authored-by: Isaac <[email protected]>

@peco-review-bot peco-review-bot Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ No issues identified by the review bot.

This branch was previously deployed

1 inactive deployment
azure-prod — bec22d81 Deployed Nov 13, 2026 by vuanhphung via review #696
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