Files
greptimedb/src/servers
discord9 d26e6d4725 perf(servers): coalesce ready Flight record batches (#9167)
* perf(servers): prototype ready-only Flight batch coalescing

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* fix(servers): bound ready Flight batch admission and cover lifecycle

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* test(servers): fix redundant error pattern assertion

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* refactor(servers): simplify Flight coalescing with append-then-check accumulator

Remove the lookahead/pending machinery and coalesce with an
append-then-check soft budget. Extract the group state into a private
BatchAccumulator so the ordinary stream loop reads as a short control
flow: append each ready batch, flush when a budget is reached.

Budgets are flush thresholds, not memory limits, so a group may exceed
a budget by the final appended batch. First-batch direct send and
singleton passthrough for a batch that starts a group already at a
budget are unchanged.

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* refactor(servers): split Flight stream into dispatcher and per-path units

FlightRecordBatchStream::flight_data_stream held two large side-by-side
branches (the verbose/ANALYZE metrics path and the plain/coalescing
path) inline, making the function hard to read. Split it into a small
dispatcher that keeps only the shared prologue (schema send, metrics
init) and the shared EOF final-metrics tail, and move each branch into a
self-contained unit:

- verbose path -> Self::verbose_metrics_stream
- plain/coalescing path -> private CoalescingBatcher (owns the
  BatchAccumulator, sent_first_batch, and schema)

Each path returns whether it reached normal EOF; the dispatcher skips
the shared final-metrics tail on any early error/failed-send exit,
preserving the exact pre-split behavior (an early return previously
exited the whole function and bypassed the tail). No behavior, metrics
ordering, or coalescing semantics change.

Add a regression test that drives flight_data_stream directly and
asserts the verbose error path does not invoke the final-metrics tail
(producer-side metrics() call count), since the public message stream
hides the tail after an error.

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* docs(servers): describe Flight stream units by behavior, not refactor history

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* perf(servers): avoid copying over-budget batches and release merged inputs

Three review-driven improvements to Flight batch coalescing:

- After a successful merge, reuse the drained vector in place
  (clear + push the merged batch) so the source batches are dropped
  before the send loop instead of staying alive across a backpressured
  send.

- A batch that is itself at/over a budget is forwarded as a singleton
  even when encountered inside an accumulation group: the accumulated
  group is flushed and sent first, then the over-budget batch. This
  avoids copying a large batch into an aggregate just to merge the small
  batches ahead of it. Under-budget append-then-check is unchanged
  (600+600 still merges).

- Strengthen two tests: the first-batch test now drives the producer
  directly and asserts the upstream poll count is exactly one at the
  first-batch send; the dictionary test now decodes the merged
  dictionary keys to assert the logical values, so a key-remapping
  regression is caught.

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

* perf(servers): raise Flight coalesce row budget to 4096

mito2 commonly emits ~2000-row batches (~32-94KiB), so a 1024-row budget
marked every such batch oversized and the coalescer forwarded them
unbatched. Measured on a local distributed cluster (2M-row table):

- full selector: 1000 -> 337 batches, p50 latency 4133 -> 3316 ms (-20%)
- range scan:    501 -> 206 batches, 1466 -> 1162 ms (-21%)
- small/olap queries (single-series, top-k, group-by): unchanged

Larger budgets (8192 rows, or 1-4MiB bytes) coalesce more batches but do
not improve latency further and slightly regress it, so 4096 rows is the
sweet spot; MAX_BYTES stays at 256KiB and MAX_BATCHES at 16.

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>

---------

Signed-off-by: discord9 <55937128+discord9@users.noreply.github.com>
2026-09-17 07:55:23 +00:00
..