prodriguezdefino opened a new pull request, #40626:
URL: https://github.com/apache/beam/pull/40626

   Problem:
   In `TentativeData.ClearOrderedListState` 
(sdks/go/pkg/beam/runners/prism/internal/engine/data.go), Prism indexed 
directly into `d.state[stateID][w]` and wrote the cleared slice back to 
`kMap[string(uKey)]` without checking whether `d.state`, `d.state[stateID]`, or 
`winMap[w]` had been initialized:
   ```go
       winMap := d.state[stateID]
       w := d.toWindow(wKey)
       kMap := winMap[w]
       data := kMap[string(uKey)]
       ...
       kMap[string(uKey)] = StateData{Bag: cleared} // panic: assignment to 
entry in nil map
   ```
   SDK harnesses (such as the Python SDK's 
`SynchronousOrderedListRuntimeState.commit`) buffer ordered-list mutations in 
memory during a bundle and flush pending `StateRequest_Clear` range requests 
before `StateRequest_Append` requests at bundle commit. When a bundle clears an 
ordered-list state cell (or range) in a window for which no prior bundle has 
persisted state on the runner, `TentativeData.state` has no map for `(stateID, 
window)`, `kMap` is nil, and Prism panics on line 336.
   
   Fix:
   Use the existing `d.clearState(stateID, wKey)` helper in 
`ClearOrderedListState` and return early when `kMap` is nil, matching 
`ClearBagState`, `ClearMultimapState`, and `ClearMultimapKeysState`.
   
   Reproduction (Python SDK on PrismRunner):
   ```python
   import apache_beam as beam
   from apache_beam.coders import VarIntCoder
   from apache_beam.options.pipeline_options import PipelineOptions
   from apache_beam.testing.util import assert_that, equal_to
   from apache_beam.transforms.userstate import OrderedListStateSpec
   from apache_beam.utils.timestamp import Timestamp
   
   class ClearOrderedListDoFn(beam.DoFn):
       EVENTS = OrderedListStateSpec("events", VarIntCoder())
   
       def process(self, element, events=beam.DoFn.StateParam(EVENTS)):
           key, (ts, op) = element
           if op == "CLEAR":
               events.clear()
               yield f"cleared:{key}"
           else:
               events.add((Timestamp(micros=ts), op))
               entries = [f"{int(t.micros)}={v}" for t, v in events.read()]
               yield f"entry:{key}:{','.join(entries)}"
   
   if __name__ == "__main__":
       options = PipelineOptions(["--runner=PrismRunner", 
"--environment_type=LOOPBACK"])
       with beam.Pipeline(options=options) as p:
           out = (
               p
               | beam.Create([("k", (30, 300)), ("k", (10, 100)), ("k", (0, 
"CLEAR"))])
               | beam.ParDo(ClearOrderedListDoFn())
           )
           assert_that(
               out,
               equal_to(["entry:k:30=300", "entry:k:10=100,30=300", 
"cleared:k"]),
           )
   ```
   


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