Repository navigation
Conversation
vaintroub
force-pushed
the
main-MDEV-38741
branch
2 times, most recently
from
October 30, 2026 02:49
c31cfc0 to
70e9cd4
Compare
vaintroub
force-pushed
the
main-MDEV-38741
branch
from
November 2, 2026 12:37
3423790 to
cbeff4c
Compare
vaintroub
force-pushed
the
main-MDEV-38741
branch
13 times, most recently
from
November 9, 2026 22:19
3092ff2 to
e7164fb
Compare
vaintroub
force-pushed
the
main-MDEV-38741
branch
6 times, most recently
from
November 13, 2026 14:19
7667edd to
4c41cfb
Compare
There was a problem hiding this comment.
🟡 Changes recommended
Unsynchronized command-state access can cause a data race, and disconnect handling can prevent an explicit KILL CONNECTION from unblocking a stalled socket write.
5 open issues
Protect m_command reads and writes with atomic or shared locking · New Preserve socket shutdown for explicit KILL CONNECTION · New Exempt COM_STMT_SEND_LONG_DATA from reply-required commands · New Limit end_statement transition to network replies · New Honor watcher OFF before killing marked connections · New
What changed in this PR
MDEV-38741 adds a client-disconnect watcher to MariaDB Server so abandoned statements can be aborted promptly, releasing connection resources and locks.
Changes:
- Adds platform-specific disconnect monitoring, a global control variable, and server lifecycle integration.
- Coordinates disconnect handling with command execution, final replies, and connection cleanup.
- Adds regression coverage and updates existing tests for disconnect logging and asynchronous cleanup.
| File | Description |
|---|---|
tests/mysql_client_test.c |
Tests half-closed, pipelined client commands. |
storage/spider/mysql-test/spider/bugfix/t/mdev_35959.test |
Accepts intentional disconnect logging. |
storage/spider/mysql-test/spider/bugfix/r/mdev_35959.result |
Updates expected suppression output. |
sql/sys_vars.cc |
Defines the disconnect watcher variable. |
sql/sql_show.cc |
Displays marked disconnects in process state. |
sql/sql_prepare.cc |
Marks prepared-statement replies uninterruptible. |
sql/sql_parse.cc |
Checks disconnects at command start and handles graceful quit. |
sql/sql_connect.cc |
Registers and removes connection watches. |
sql/sql_class.h |
Declares disconnect state and handling methods. |
sql/sql_class.cc |
Implements disconnect-triggered cancellation and state reset. |
sql/protocol.cc |
Marks final replies uninterruptible. |
sql/mysqld.h |
Exposes watcher configuration and instrumentation. |
sql/mysqld.cc |
Integrates watcher startup, shutdown, and instrumentation. |
sql/disconnect_watcher.h |
Defines watcher interfaces and platform stubs. |
sql/disconnect_watcher.cc |
Implements platform-specific monitoring and batched cancellation. |
sql/CMakeLists.txt |
Includes the watcher implementation in the build. |
mysql-test/suite/unit/suite.pm |
Adds disconnect suppression for unit tests. |
mysql-test/suite/sysschema/t/pr_ps_setup_show_enabled.test |
Excludes watcher instrumentation from enabled-thread output. |
mysql-test/suite/sysschema/r/pr_ps_setup_show_enabled.result |
Updates expected thread filtering. |
mysql-test/suite/sys_vars/t/disconnect_watcher_basic.test |
Tests variable scope and accepted values. |
mysql-test/suite/sys_vars/r/sysvars_server_notembedded.result |
Records watcher variable metadata. |
mysql-test/suite/sys_vars/r/sysvars_server_notembedded,aix.rdiff |
Omits the unsupported variable on AIX. |
mysql-test/suite/sys_vars/r/disconnect_watcher_basic.result |
Records variable-test expectations. |
mysql-test/suite/rpl/t/rpl_ssl1.test |
Ends replication-user sessions before cleanup. |
mysql-test/suite/rpl/t/rpl_semi_sync_shutdown_await_ack.test |
Accepts intentional disconnect logging. |
mysql-test/suite/rpl/t/rpl_password_boundaries.test |
Ends replication-user sessions before cleanup. |
mysql-test/suite/rpl/t/rpl_get_lock.test |
Accepts Windows connection-reset errors. |
mysql-test/suite/rpl/t/rpl_fail_register.test |
Tolerates dump threads ending before explicit kill. |
mysql-test/suite/rpl/t/rpl_dump_thread_disconnect.test |
Tests dump-thread cancellation and logging levels. |
mysql-test/suite/rpl/t/max_binlog_total_size.test |
Tolerates asynchronous dump-thread termination. |
mysql-test/suite/rpl/r/rpl_ssl1.result |
Removes warnings after session cleanup. |
mysql-test/suite/rpl/r/rpl_semi_sync_shutdown_await_ack.result |
Updates suppression output. |
mysql-test/suite/rpl/r/rpl_password_boundaries.result |
Removes warnings after session cleanup. |
mysql-test/suite/rpl/r/rpl_fail_register.result |
Removes nondeterministic kill output. |
mysql-test/suite/rpl/r/rpl_dump_thread_disconnect.result |
Records cancellation and logging expectations. |
mysql-test/suite/rpl/r/max_binlog_total_size.result |
Removes nondeterministic kill output. |
mysql-test/suite/perfschema/t/threads_mysql.test |
Filters the platform-dependent watcher thread. |
mysql-test/suite/perfschema/r/threads_mysql.result |
Updates expected thread filtering. |
mysql-test/suite/mariabackup/nolock_ddl_during_backup_end.test |
Accepts intentional disconnect logging. |
mysql-test/suite/mariabackup/nolock_ddl_during_backup_end.result |
Updates suppression output. |
mysql-test/suite/innodb/t/xa_recovery.test |
Checks disconnect cancellation with a timeout fallback. |
mysql-test/suite/innodb/t/innodb_bug38231.test |
Accepts disconnects during lock waits. |
mysql-test/suite/innodb/r/xa_recovery.result |
Updates conditional-query output. |
mysql-test/suite/innodb/r/innodb_bug38231.result |
Updates suppression output. |
mysql-test/suite/federated/federatedx_pushdown_upd_del.test |
Accepts disconnects caused by remote timeouts. |
mysql-test/suite/federated/federatedx_pushdown_upd_del.result |
Updates suppression output. |
mysql-test/mariadb-test-run.pl |
Stops globally suppressing watcher disconnect warnings. |
mysql-test/main/ssl_timeout.test |
Accepts intentional timeout-related disconnects. |
mysql-test/main/ssl_timeout.result |
Updates suppression output. |
mysql-test/main/sp_notembedded.test |
Accepts disconnects during stored-procedure waits. |
mysql-test/main/sp_notembedded.result |
Updates suppression output. |
mysql-test/main/mysqltest.test |
Accepts exit with a statement still running. |
mysql-test/main/mysqltest.result |
Updates suppression output. |
mysql-test/main/mysqldump.test |
Accepts disconnects after import failures. |
mysql-test/main/mysqldump.result |
Updates suppression output. |
mysql-test/main/mysqld--help.result |
Documents the watcher option and default. |
mysql-test/main/mysqld--help,aix.rdiff |
Adjusts AIX-specific help expectations. |
mysql-test/main/mysql_client_test.test |
Accepts intentional client-test disconnects. |
mysql-test/main/mysql_client_test.result |
Updates suppression output. |
mysql-test/main/mysql_client_test_nonblock.test |
Accepts nonblocking client-test disconnects. |
mysql-test/main/mysql_client_test_nonblock.result |
Updates suppression output. |
mysql-test/main/mysql_client_test_comp.test |
Accepts compressed client-test disconnects. |
mysql-test/main/mysql_client_test_comp.result |
Updates suppression output. |
mysql-test/main/loaddata.test |
Accepts disconnects during local data loading. |
mysql-test/main/loaddata.result |
Updates suppression output. |
mysql-test/main/disconnect_wait_kinds.test |
Tests CPU-bound work, table waits, and idle disconnects. |
mysql-test/main/disconnect_wait_kinds.result |
Records cancellation and idle-client expectations. |
mysql-test/main/disconnect_thread_reuse.test |
Tests disconnect-state isolation across cached-thread reuse. |
mysql-test/main/disconnect_thread_reuse.result |
Records thread-reuse expectations. |
mysql-test/main/disconnect_thread_reuse.opt |
Selects one thread per connection. |
mysql-test/main/disconnect_sp.test |
Tests cancellation despite stored-procedure error handlers. |
mysql-test/main/disconnect_sp.result |
Records procedure cancellation and logging expectations. |
mysql-test/main/disconnect_lock_wait.test |
Tests lock-wait cancellation and runtime disabling. |
mysql-test/main/disconnect_lock_wait.result |
Records lock-wait and logging expectations. |
mysql-test/main/disconnect_lock_wait_idle.test |
Tests command-start and final-reply timing. |
mysql-test/main/disconnect_lock_wait_idle.result |
Records synchronized disconnect expectations. |
mysql-test/main/disconnect_lock_owner.test |
Tests rollback and release of owned locks. |
mysql-test/main/disconnect_lock_owner.result |
Records lock-release expectations. |
mysql-test/main/disconnect_client_killed.test |
Tests cancellation after client-process termination. |
mysql-test/main/disconnect_client_killed.result |
Records process-termination expectations. |
mysql-test/main/disconnect_client_killed.opt |
Enables named-pipe testing where supported. |
mysql-test/main/disconnect_client_killed.combinations |
Defines TCP, socket, and pipe variants. |
mysql-test/main/dirty_close.test |
Accepts intentional abrupt disconnects. |
mysql-test/main/dirty_close.result |
Updates suppression output. |
mysql-test/include/rpl_init.inc |
Adds per-server replication disconnect suppression. |
mysql-test/include/mtr_warnings.sql |
Keeps watcher warnings outside global suppression. |
mysql-test/include/have_disconnect_watcher.inc |
Gates tests on an enabled watcher. |
mysql-test/include/end_user_sessions.inc |
Adds user-session termination and waiting helper. |
mysql-test/include/disconnect_watcher_value.inc |
Detects watcher availability and enabled state. |
include/my_net.h |
Defines Windows write-side socket shutdown constant. |
extra/mariabackup/xtrabackup.cc |
Keeps debug DDL connected through a compound statement. |
Review effort: Balanced
vaintroub
force-pushed
the
main-MDEV-38741
branch
from
November 14, 2026 00:03
4c41cfb to
b6d1660
Compare
vaintroub
force-pushed
the
main-MDEV-38741
branch
from
November 14, 2026 01:23
b6d1660 to
30ae4b4
Compare
The debug thread of mariabackup that emulates a DDL sends several statements in one query, and closes its connection as soon as the first of them returned. The server used to run the rest. A server that aborts the statement of a client that is gone does not, and mariabackup.innodb_ddl_on_intermediate_table hangs, as the debug sync signals the main thread waits for do not come. Run the statements in one BEGIN NOT ATOMIC block, so that the client waits for all of them. The ALTER of that test fails with a lock wait timeout on purpose, which the handler of the block ignores, as the thread did before. Assisted-by: Claude:claude-sonnet-5-5
A watcher thread subscribes to the OS notification that a client has gone (e.g. TCP FIN or RST for a TCP socket, a gone client process for a named pipe) and aborts the running statement like KILL CONNECTION does. Controlled by the global variable disconnect_watcher. Details in PR#6035. Assisted-by: Claude:claude-sonnet-5-5
The global suppressions of "Aborted connection", in mariadb-test-run.pl and mtr_warnings.sql, hid the line that the client disconnect watcher writes when it aborts a command: "Aborted connection N to db: 'x' user: 'u' host: 'h' (Client disconnected)". Nothing showed when the watcher aborted a connection that it should have left alone. main.locale found one, because its server log is in German and the English entry did not match. Make the two entries skip a line that ends in "(Client disconnected)". Other aborted connections are suppressed as before. The tests that drop a client on purpose accept the reason with mtr.add_suppression(), details in PR#6035. Assisted-by: Claude:claude-sonnet-5-5
vaintroub
force-pushed
the
main-MDEV-38741
branch
from
November 14, 2026 10:28
30ae4b4 to
5d5fbb7
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


MDEV-38741 Abort the running statement when its client disconnects
A watcher thread subscribes to the OS notification that a client has gone (for example TCP FIN or RST for a TCP socket, a gone client process for a named pipe) and aborts the running statement as
KILL CONNECTIONwould. The problem, the behavior, the limits and thedisconnect_watchervariable are described in MDEV-38741. This page is for the review: how it works, what it costs, what was tested.Implementation
Flags and the check at command start
THD::disconnect_flagsis anAtomic_relaxed<uint8>with two bits, reset when the THD is reused. The watcher setsDISCONNECT_MARKED.DISCONNECT_UNINTERRUPTIBLEis set byTHD::set_disconnect_uninterruptible()when the last reply of a command is sent, fromProtocol::end_statement(), and fromCOM_STATISTICSandCOM_STMT_PREPARE(send_prep_stmt()), which write their replies themselves.THD::check_disconnect()is called fromdispatch_command()afterreset_kill_query(). It clearsDISCONNECT_UNINTERRUPTIBLE, and kills the connection if it is marked and the command expects an answer (command_expects_answer(): notCOM_SLEEP,COM_QUIT,COM_STMT_CLOSE).Ordering without a lock
The connection thread stores the command and then clears
DISCONNECT_UNINTERRUPTIBLEwith a releasefetch_and. The watcher setsDISCONNECT_MARKEDwith an acquirefetch_orand then loads the command. Both are read-modify-writes of one atomic, so they have a single order. If the watcher's comes second, it sees the command and aborts it. If it comes first, the thread'sfetch_andreturns the mark and the thread aborts the command itself. A statement cannot run for a gone client without one of them noticing.LOCK_thd_killis taken only when the mark is set.m_commandis still a plain enum that is read without a lock, as it is by the processlist.Finding and killing the connection
The watcher finds the THD by thread id like
KILLdoes, and may act on a stale event: the id of a gone connection is not found, and a reused id takes 2^32 new connections. It marks the connections of a round in one scan of the thread list under the read lock, and kills outside of it, with the THD found again by its id, because aborting writes the error log, calls the storage engines and can wait for the victim. The kill takesLOCK_thd_killandLOCK_thd_data, checks the command again and callsTHD::kill_on_disconnect(), which usesawake_no_mutex(KILL_CONNECTION).A connection that is already being killed is left alone.
KILL CONNECTIONshuts the socket of its victim, which the watcher reports, and a second awake of the dying thread would wait for it inabort_current_cond_wait()for up to 2 seconds. That left a killedSLEEP()ofmain.processlistvisible tomain.processlist_notembedded.The reason "Client disconnected" is logged once, by the abort itself, and only if nothing else is killing the connection yet. The socket is not shut down for it, the client is gone already and the thread must still read what the client sent before it left. For
COM_BINLOG_DUMPthe reason is "BINLOG DUMP client disconnected", at the level oflog_warnings=4.Galera (wsrep) connections are never marked.
Platforms
EPOLLRDHUPis requested, as a close and a crashed client can be only a FIN. Sockets are in the oneshot mode.WSAEventSelect(FD_CLOSE). The API is from ntdll, sparsely documented, and loaded withGetProcAddress, with no SDK header. A thread of its own takes the completions. The completion key is the connection id by value. A connection that ends ends the selection and cancels its packet, which drops a queued completion.OpenProcessis denied, the client is impersonated for it, which needsSeImpersonatePrivilege; a service has it enabled (verified). Otherwise a warning is logged once and the connections of such a client are not watched.EV_EOFof a read filter withEV_CLEARand the low water mark out of reach. macOS uses the socket filterEVFILT_SOCK(NOTE_CONNRESET | NOTE_READCLOSED), which reports a reset and a shutdown of the read side, never data, because XNU clamps the low water mark to the receive buffer. It is private to XNU; libdispatch uses it too.Cost
epoll_ctlpair on Linux, akeventpair on the BSDs, and on Windows an event handle forFD_CLOSE(WSAEventSelect) and a wait completion packet, created at login and closed when the connection ends.THD::disconnect_flags, at command start and when the last reply is sent, and no mutex.Optimizations
Throttling delay and the FIN and COM_QUIT race
After one round of events the watcher thread waits 50 ms (a
poll()of its stop pipe on Linux and the BSDs, aSleep()on Windows, rounded up to a timer tick). A statement that is aborted by the watcher takes up to that long longer to be aborted, which does not matter for a statement that runs for seconds. Many clients close their socket right afterCOM_QUIT, so the FIN can already be there before the server has read it, which is a race. The wait lets that connection remove its socket from the set first, which drops the pending event, so the watcher does not look up the connection for every normal disconnect. It does not remove all of them: with a thread pool that falls behind, a connection can wait longer than the delay before itsCOM_QUITis read, and then the event is handled. The events of a round are served by one scan (below).A client that follows the graceful disconnect sequence (
COM_QUIT, then wait for the server to close, then close) hardly races, as the server closes first, and the client has noTIME_WAITsocket that holds a port. MariaDB Connector/J does this, reading until the server closes for up to about 10 ms. MariaDB Connector/Node.js does not: it destroys the socket right after it sendsCOM_QUIT.One scan for a round
A lookup by thread id scans all connections, so the events of a round are served by one scan, with the ids sorted and found by binary search, instead of one scan per event. The scan only notes the disconnects and takes no mutex of the THD.
Benchmarks
Connections per second with
disconnect_watcherON compared with OFF, switched at runtime. sysbench connects and disconnects only ("connect only"), or connects, runsDO 1orSELECT 1and disconnects ("DO 1", "SELECT 1"). Three repetitions per mode unless stated, the run to run noise is about 5%. Linux numbers are from a RelWithDebInfo build with the thread pool and a unix socket unless stated. The delay in the code is 50 ms; the delay used for each measurement is stated, the 5, 15 and 100 ms measurements were made with a temporary setting.Delay, Linux thread pool, unix socket
DO 1DO 1At 1024 clients the server limit on connections was raised: sysbench does not wait for the server to close, and the thread pool cannot keep up, so closed connections pile up, with the watcher OFF too. The pile-up is part of what these runs measure. The OFF rate varies by up to 10% between configurations, so single percentages are not exact; at 256 clients the ON and OFF ranges overlap for 50 and 100 ms, and at 1024 for 50 and 100 ms.
Events that reach the scan (256 clients, connect only, 3 x 10 s): 72% of the disconnects with 5 ms (1.9 s of scan time in 30 s), 32% with 15 ms (0.61 s), 11% with 50 ms (0.18 s). One scan serves 430 to 630 events. The watcher thread itself uses 0.26% of the CPU samples of the server (
perf, 15 ms); the cost is the writers of the thread list waiting for the scan.A delay of 100 ms (not used), Linux unix socket
3 repetitions per mode,
thread_cache_size=1024for one thread per connection:DO 1SELECT 1DO 1SELECT 1Compared with 50 ms the picture is the same within the noise of about 5% to 10%: the thread pool storm at 1024 clients improved (−9.4% to −6.9%), the one thread per connection rows at 1024 clients are a little worse (for example connect only −0.6% to −5.0%), and 100 ms is not clearly better than 50 ms across the board. Most ON and OFF ranges overlap; the separated ones are the thread pool at 1024 clients for connect only and
SELECT 1, and for one thread per connectionDO 1.thread_pool_size, Linux unix socket, 50 msThread pool, ON vs OFF, 3 repetitions per mode (the default size is the number of CPUs, 16 here; the default column is from the earlier 50 ms runs):
DO 1DO 1SELECT 1SELECT 1With 64 threads the cost is about 3% in every row but connect only at 1024 clients (−5.9%), and the OFF rate of that row is higher (connect only, 1024 clients: 82,842 with 16, 96,846 with 32 and 99,116 connections per second with 64 threads, taken from different runs). The 32 thread run is mixed (connect only at 1024 clients −13.8%, with separated ranges). A larger pool probably keeps up with the clients better, so fewer disconnects are pending when the watcher looks; I did not test that.
Thread handling, thread cache and
SELECT 1, Linux unix socket, 50 msSELECT 1DO 1thread_cache_size=1024thread_cache_size=1024DO 1thread_cache_size=1024SELECT 1The runs scatter by about 10% (with the default cache, 1024 clients, connect only: OFF from 93,691 to 119,637 connections per second), and most ON and OFF ranges overlap; the thread pool with
SELECT 1at 1024 clients (ON 74,803 to 82,347, OFF 84,567 to 85,488) does not. The thread cache removes the creation of a thread for each connection: the OFF rate ofDO 1rose from 88,000 to 104,700 per second with 1024 clients.Other setups, 15 ms
SO_LINGER {1, 0}so that the client has noTIME_WAIT: connect only 64 clients −2.8%, 256 clients −1.6%;DO 164 clients −2.6%, 256 clients −2.5%.SO_LINGER 0(noTIME_WAIT), connect only, 64 clients: −1.6% with 5 ms, −1.3% with 15 ms, −1.5% with 50 ms, within the noise. The rate is 22,000 to 24,000 connections per second with the watcher ON or OFF. With 256 clients, sysbench's opening burst of connects is refused by Windows about half of the time (error 10061, with the watcher OFF too), because the listen backlog is capped (a test listening withSOMAXCONN_HINT(back_log)had no refused connects in 10 runs; that is MDEV-42258, merged in 10.11 and not yet in this branch), so the script retries a refused connect: −0.9% (5 runs per mode, 21,898 OFF and 21,705 ON, 50 ms).Earlier measurements
SELECT 1and disconnect with 32 clients over a unix socket was 37% slower with the watcher without the delay, and 3% slower with 5 ms (8 clients: 7%, and less than 1%).LOCK_thd_killacquisitions per 1000 statements: 1001 with the feature, 1001 with the watcher OFF.Not measured: kqueue, Windows sockets with more than 256 clients, TCP without the
SO_LINGERchange.Commits
BEGIN NOT ATOMICblock. Without itmariabackup.innodb_ddl_on_intermediate_tablehangs with the feature.The memory leak of a local statement that fails after its metadata (found with the SQL service while testing this) is MDEV-42087, in its own PR.
Tests
New tests are in
main(disconnect_*),sys_vars.disconnect_watcher_basic,rpl.rpl_dump_thread_disconnectandmysql_client_test. They cover a client that leaves during a lock wait, a CPU-bound statement, a table lock wait, a stored procedure handler, an idle client, a killed client process (TCP, unix socket, named pipe), a reused thread, pipelined commands, and a command that already sent its reply.innodb.xa_recoveryno longer needs the work-around for this issue (the shortenedinnodb_lock_wait_timeout) when the watcher is ON: the disconnect aborts the lock wait, and the test checks that the lock is released.The tests need the watcher ON. The global mtr suppressions of
Aborted connectionno longer match a line that ends in(Client disconnected), because they hid the aborts of ordinary clients. Tests that drop a client on purpose accept the reason withmtr.add_suppression, among themmain.mysqldump(mariadb-importcan leave aLOAD DATArunning when it fails, fixed in MDEV-42164) andfederated.federatedx_pushdown_upd_del(the master gives up afternet_read_timeoutwhile the slave is still running).rpl_init.incaccepts it on the servers of the replication tests, because a stopped replica closes its connection on purpose.There is no deterministic test that
COM_STMT_CLOSEandCOM_QUITsent in one write followed by a half-close are not aborted. It needs a sync point in the connection thread.Verification and gaps
main 1st, the disconnect tests, bothmysql_client_testvariants and relatedmaintests, three runs each, all pass. Run on the final design on Windows Debug before the last rebases.aarch64-macos, release build): the watcher tests pass, includingmain.disconnect_*,dirty_close,aborted_clients,mysql_client_testandsys_vars.disconnect_watcher_basic.disconnect_lock_wait_idleneeds a debug build and is skipped. The failures of that builder (sys_vars.path_basic,main.sp-security,perfschema.socket_summary_by_instance_func) also happen onmain.disconnect_watcher.hare used). A watcher for them is not implemented, as it cannot be tested yet.amd64-freebsd-14): does not compile at the moment, on this PR and onmain, because the columnstore configure step requiresgettid(). TheEV_EOFbranch has not run.KILL.Follow-ups
disconnect_watcher.ccare similar; a shared poll layer could remove the duplication.m_commandcould be madeAtomic_relaxed; it is the other half of the race that the flags order.🤖 Generated with Claude Code