Ma77Ball opened a new issue, #8673:
URL: https://github.com/apache/texera/issues/8673

   ### Task Summary
   
   > **In one sentence:** columnar execution processes a whole batch (~10k 
rows) per DP-thread step, so pause, breakpoints, and backpressure land at batch 
boundaries instead of per row like the row path; this task restores 
fine-grained (near per-row) control by making columnar operators resumable 
mid-batch.
   
   **Background.** The opt-in columnar (Apache Arrow) path (see #8556, 
discussion #8571) preserves Amber's pipelining: operators stay concurrent 
actors, batches stream under credit-based backpressure (drained one batch per 
DP-loop step), and blocking edges are unchanged. But it coarsens one thing. The 
row path yields to control messages between individual tuples (`outputOneTuple` 
/ `inputManager.getNextTuple`), while the columnar path runs an entire batch in 
a single DP step (`processColumnarBatch`, `emitOneColumnarBatch`). So a pause, 
breakpoint, or backpressure check can only land between batches, not mid-batch. 
For a debuggability-first engine that is a real regression in control 
granularity.
   
   **What was measured (why this is worth doing, and cheap).** A standalone 
20M-row filter loop, JDK 17, x86, monotonic clock:
   
   | Filter loop over 20M ints | Time | vs no-check |
   | --- | --- | --- |
   | raw `int[]`, check every row | 20.1 ms | 1.00x |
   | Arrow `IntVector`, no check | 92.2 ms | 1.00x |
   | Arrow `IntVector`, check every row | 92.8 ms | 1.01x |
   | Arrow `IntVector`, check every 512 (chunked) | 126.3 ms | 1.37x (slower) |
   
   - A `volatile` pause-flag check **every row costs ~1%**. On x86 a volatile 
read is a cached load (fences are only for writes) and the never-taken branch 
predicts perfectly, so the "per-row check kills vectorization" intuition does 
not hold on the JVM.
   - **Chunking (checking every K rows via a nested loop) was 37% slower** on 
the Arrow path, a JIT artifact where the nested loop loses the bounds-check 
elimination the flat loop keeps. So the correct shape is a flat loop with a 
per-row check, not chunking.
   
   The per-row check is essentially free; the work is the resumability 
plumbing, not the check.
   
   ### Proposed solution / design
   
   1. **Per-row pause check** in the columnar operator loops (filter mask, 
decode-into-state, gather), kept as a flat loop (no chunking).
   2. **Resumable columnar processing:** the columnar entry point returns 
partial progress plus a row cursor (or accepts a start cursor), so an operator 
can stop mid-batch and be re-entered where it left off.
   3. **DP-loop cooperative yield:** on a pause or backpressure signal 
mid-batch, save the cursor, return to the DP main loop (input selection, 
control handling, backpressure check), and resume the same batch on the next 
step, exactly as the row path already advances a cursor through a batch tuple 
by tuple.
   4. **Keep checkpoints at batch boundaries.** Pause is cursor-based and may 
be mid-batch, but epoch/marker checkpoints and reconfiguration stay aligned to 
message boundaries so replay and exactly-once are unaffected.
   5. **Make the check frequency a tunable** (default per-row on x86). On 
weak-memory architectures (ARM) a volatile read may compile to a fenced load 
and not be free, so allow checking every N rows.
   
   **Scope.** This is an engine change (the DP main loop plus the columnar 
operator contract), not a drive-by, and should land after the columnar series 
(#8556) merges. Related discussion: #8571.
   
   ### Task Type
   - [x] Performance


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to