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

   ### What happened?
   
   A loop cannot run when a Java/Scala built-in operator (e.g. `Limit`) is 
inside the loop body. The Loop End worker crashes on the first iteration:
   
   ```
   RuntimeError: no loop-back state URI configured for LoopStart ''
     (have: ['LoopStart-operator-4d423fa9-...'])
   ```
   
   The worker enters an error pause and the loop never iterates. A Python-only 
loop body works fine.
   
   ### How to reproduce?
   
   Run any loop with a Scala operator between Loop Start and Loop End, e.g.:
   
   ```
   TextInput ──▶ LoopStart ──▶ Limit ──▶ LoopEnd
                     ▲          (Scala)     │
                     └──── back-edge ───────┘
   ```
   
   ### Root cause
   
   Per-iteration loop state rides a `StateFrame` envelope — `loop_counter` 
(nesting depth countdown) and `loop_start_id` (the back-jump target) — 
materialized as their own columns next to `content` (`State` schema, #5900). 
The **Python** worker carries the envelope on every hop. The **Scala** side 
strips it at every seam: `StateFrame` has no envelope fields, so a JVM hop 
rebuilds states with the defaults `(0, "")`.
   
   | Seam (Scala) | What it does today |
   |---|---|
   | `StateFrame` (`DataPayload.scala`) | no `loopCounter` / `loopStartId` 
fields |
   | `InputPortMaterializationReaderThread` | rebuilds via 
`State.fromTuple(row)` — columns dropped |
   | `DataProcessor.processInputState` | forwards `processState` output without 
the incoming envelope |
   | `OutputManager.saveStateToStorageIfNeeded` | writes `state.toTuple()` — 
defaults `(0, "")` |
   | `NetworkOutputBuffer.sendState` | builds `StateFrame(state)` — defaults |
   | `PythonProxyClient` / `PythonProxyServer` | Arrow flight bridge drops the 
columns in both directions |
   
   So `LoopStart → Limit → LoopEnd`: LoopStart stamps `(0, LoopStart-id)` → the 
`Limit` hop re-emits `(0, "")` → LoopEnd captures `loop_start_id = ""` → the 
back-jump write-address lookup (`InitializeExecutorRequest.loopStartStateUris`) 
fails with the error above.
   
   In a **nested** loop the zeroed `loop_counter` is just as harmful: an 
enclosing loop's state crossing a Scala hop inside the inner body loses its 
depth, so the inner Loop End mis-consumes it instead of passing it through.
   
   ### Expected behavior
   
   | | before | after |
   |---|---|---|
   | `LoopStart → Limit → LoopEnd` (3 iters) | worker error, 0 iterations | 3 
iterations, LoopEnd materializes 3 rows |
   | nested 3×3 with `Limit` in inner body | inner LoopEnd mis-consumes outer 
state | 9 outer rows / 3 inner rows |
   
   The envelope columns already exist in the materialized State schema and on 
the Arrow flight wire — a JVM operator only ever needs to **carry them through 
unchanged** (loop operators are Python-only; the +1/−1 bookkeeping lives in the 
Python runtime).
   


-- 
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