Avoid holding the async-insert shard lock during pool admission by VrtxOmega · Pull Request #118352 · ClickHouse/ClickHouse · GitHub
Skip to content

Avoid holding the async-insert shard lock during pool admission - #118352

Open
VrtxOmega wants to merge 2 commits into
ClickHouse:masterfrom
VrtxOmega:fix/async-insert-shard-lock
Open

Avoid holding the async-insert shard lock during pool admission#118352
VrtxOmega wants to merge 2 commits into
ClickHouse:masterfrom
VrtxOmega:fix/async-insert-shard-lock

Conversation

@VrtxOmega

Copy link
Copy Markdown

When async-insert workers are saturated, a producer can wait for pool admission while holding a queue-shard mutex. Other inserts sharing that shard then block even when they only need to buffer data. Move pool admission outside the shard lock while retaining backpressure on the submitting producer.

Track batches removed by producers and deadline workers until their data is destroyed. This allows SYSTEM FLUSH ASYNC INSERT QUEUE to wait for batches that have already left the shard queue but have not yet entered the worker pool, without holding shard locks during that wait.

Add a single-worker integration fixture with eight parameterized cases for saturation, global/table-specific flushes, both wait_for_async_insert modes, size/deadline batch removal, and parse-error cleanup. A new failpoint makes the gap before pool admission observable.

Local validation used Debug builds with failpoints enabled, Clang 22.1.8, and base 58d0e8cb852acbd70e3207cf297fb2d4e26f88c8:

  • Both original and patched binaries compiled and passed a version-query smoke test.
  • On the original binary, all four saturation cases reproduced the unrelated insert's 30-second HTTP timeout. There were no fixture setup errors in that run.
  • On the patched binary, all eight regression cases passed, including size/deadline handoff and parse-error cleanup.
  • The complete upstream style job passed all 15 checks.
  • Separate local shutdown checks passed with flush_on_shutdown enabled and disabled, verifying graceful termination, retained/discarded buffered rows, and pending-insert cleanup.
  • The existing test_async_insert_memory::test_memory_usage integration test passed.

A separate synthetic probe issued 16 unrelated inserts while one flush worker was deliberately paused. Before releasing that worker, the original completed 0/16 and the patched build completed 16/16. Median latency was 2316.75 ms versus 7.67 ms. The forced pause contributes to these timings; this small experiment establishes progress under saturation, not production throughput or an overall memory bound. Sanitizer coverage and broader workload characterization remain outside this validation.

Closes: #117927

Changelog category (leave one):

  • Bug Fix (user-visible misbehavior in an official stable release)

Changelog entry (a user-readable short description of the changes that goes into CHANGELOG.md):

Prevent asynchronous inserts that only need to buffer data from being blocked by another insert waiting for a flush worker while holding their shared queue lock. Ensure a global forced flush waits for batches removed from the queue that are still waiting for a worker.

Track detached batches through their lifetime so a global forced flush waits for work awaiting pool admission. Add deterministic saturation and handoff regression coverage.

Related: ClickHouse#117927
@CLAassistant

CLAassistant commented Sep 6, 2026

Copy link
Copy Markdown

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Sep 6, 2026

Copy link
Copy Markdown

Codex Review Summary

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review Completed 2026-09-06T01:20:07.963332Z 9cc5b1c PR opened
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@clickhouse-gh clickhouse-gh Bot added the comp-async-insert Asynchronous INSERT buffering/queueing and flush semantics. label Sep 6, 2026
@zlareb1

zlareb1 commented Sep 6, 2026

Copy link
Copy Markdown
Member

TL;DR: the global-flush guarantee looks sound (the counter is published under the shard mutex before queue erasure, and the decrement in ~InsertData runs on every path including a schedule throw and pool finalize), but the table-specific flush keeps its old gap while this change slightly widens it.

SYSTEM FLUSH ASYNC INSERT QUEUE <table> (the flush(tables) overload) does not consult in_flight_flushes: a batch that a producer has removed from the queue but not yet admitted to the pool is invisible to it, so the statement can return while accepted rows for that table are still unflushed, and a subsequent SELECT misses them. The same window existed before for removed-and-scheduled-but-not-yet-run jobs (the in-code note "jobs scheduled before the call of 'flush' are not counted" covers it), but moving admission outside the shard lock lengthens the pre-admission phase of that window. Since the per-shard counter cannot distinguish tables, waiting on it there would over-wait — if that trade-off is why the table-specific path was left out, a short code comment on flush(tables) mirroring the existing note would make the asymmetry explicit for the next reader.

Clarify that removed batches are outside the table-specific wait set, including batches waiting for pool admission. The shard-wide in-flight counter also covers unrelated tables.

Related: ClickHouse#118352 (comment)

Copy link
Copy Markdown
Author

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

Labels

comp-async-insert Asynchronous INSERT buffering/queueing and flush semantics.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Async inserts stall for minutes: pushDataChunk blocks on a full flush thread pool while holding the queue shard mutex

4 participants