Jungtaek Lim created SPARK-59919:
------------------------------------

             Summary: Offset log format v2 does not preserve stateful shuffle 
partitions across query restarts
                 Key: SPARK-59919
                 URL: https://issues.apache.org/jira/browse/SPARK-59919
             Project: Spark
          Issue Type: Bug
          Components: Structured Streaming
    Affects Versions: 4.2.0
            Reporter: Jungtaek Lim


# Description

Offset log format v2 does not persist the stateful shuffle partition count used 
by a streaming query.

Consequently, when a stateful query is restarted with a different value of 
spark.sql.shuffle.partitions, Spark uses the current session value instead of 
the partition count recorded by the original execution. This changes the 
state-store partitioning and can make the checkpoint unrecoverable.

This is independent of offline state repartitioning. A normal stop-and-restart 
reproduces it.

Offset log v1 persists:

spark.sql.shuffle.partitions =
spark.sql.streaming.internal.stateStore.partitions

through the rebindSQLConfsSessionToOffsetLog mapping. However, 
OffsetSeqMetadataV2.apply copies only relevantSQLConfs and omits this rebinding.

During restart, IncrementalExecution.numStateStores cannot find the persisted 
value and falls back to the current session’s spark.sql.shuffle.partitions.

# Reproduction

1. Enable offset log format v2.
2. Start a stateful streaming aggregation with spark.sql.shuffle.partitions=5.
3. Process and commit at least one batch.
4. Stop the query.
5. Set spark.sql.shuffle.partitions=10.
6. Restart the query from the same checkpoint and process another batch.

For example:

withSQLConf(
SQLConf.STREAMING_OFFSET_LOG_FORMAT_VERSION.key -> "2",
SQLConf.SHUFFLE_PARTITIONS.key -> "5")

{ // Start a stateful aggregation, process data, and stop it. }

withSQLConf(
SQLConf.STREAMING_OFFSET_LOG_FORMAT_VERSION.key -> "2",
SQLConf.SHUFFLE_PARTITIONS.key -> "10")

{ // Restart from the same checkpoint and process more data. }

# Actual behavior

Spark reports:

Conf 'spark.sql.streaming.internal.stateStore.partitions' was not found
in the offset log. Using existing session conf value '10'.

The restarted physical plan uses:

Exchange hashpartitioning(..., 10), REQUIRED_BY_STATEFUL_OPERATOR

It then attempts to load state partitions that were never created by the 
original five-partition execution and fails, for example:

CANNOT_LOAD_STATE_STORE.CANNOT_READ_DELTA_FILE_NOT_EXISTS
.../state/0/6/1.delta does not exist

# Expected behavior

The query should retain the original five state-store partitions and restart 
successfully, regardless of the current session value of 
spark.sql.shuffle.partitions.

# Scope and compatibility

Offset log format v2 is not the default in Spark 4.2.0; the default remains v1. 
Therefore, default v1 queries are not affected.

However, any query using or requiring offset log format v2 can produce a 
checkpoint that cannot be restarted safely when the session shuffle-partition 
configuration changes.

This is a regression in the offset-log v2 implementation introduced under 
SPARK-54583 and is separate from the state-repartition-specific failure tracked 
by SPARK-59662.

# Suggested resolution
 - Make v2 persist the same stateful shuffle-partition rebinding as v1.
 - Add a regression test covering a normal 5-partition → 10-partition session 
restart.
 - Define recovery behavior for existing v2 checkpoints that already lack the 
configuration. Fixing only future writes will not repair those checkpoints. 
Recovery may need to infer the partition count from committed operator/state 
metadata before falling back to
the current session configuration.

# Related issues
 - SPARK-54583
 - SPARK-59662



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to