Francis created FLINK-41424:
-------------------------------

             Summary: ForSt: support dropping keyed state for removed state 
descriptors
                 Key: FLINK-41424
                 URL: https://issues.apache.org/jira/browse/FLINK-41424
             Project: Flink
          Issue Type: Improvement
          Components: Runtime / State Backends
    Affects Versions: 2.2.1
            Reporter: Francis


h3. Problem

Removing a state descriptor from a keyed operator does not remove its data. The 
column family is restored from the checkpoint and carried into every future 
checkpoint, even though no code can reach it.

We run a Flink 2.2.1 job on ForSt with the async state API, incremental 
checkpoints and CLAIM restores. Over time we removed three {{ValueState}} 
descriptors from a single keyed operator. Around 50% of our checkpoint file 
size was state from those removed descriptors.

h3. Existing options

None of these fix it:
* {{allowNonRestoredState}} only works per operator.
* The State Processor API means stopping the job and rewriting a savepoint, and 
it does not support ForSt.
* {{applyToAllKeys}} is not available on the async ForSt backend.
* Adding a TTL to the existing state needs a state migration, which async ForSt 
does not support yet.

h3. Current workaround

We re-register the removed descriptors in {{open()}} and run Flink's own 
rescale code on just those column families, with an empty target key group 
range:

{code:java}
val states = deadStateNames.map {
    runtimeContext.getState(ValueStateDescriptor(it, 
BYTE_PRIMITIVE_ARRAY_TYPE_INFO))
}.filterIsInstance<ForStValueState<*, *, *>>()

// AsyncExecutionController#switchContextListener is the keyed backend 
(package-private)
val backend = readField(
    states.first().stateRequestHandler,
    AsyncExecutionController::class.java,
    "switchContextListener",
) as ForStKeyedStateBackend<*>

// ForStKeyedStateBackend#db is protected
val db = readField(backend, ForStKeyedStateBackend::class.java, "db") as RocksDB

ForStIncrementalCheckpointUtils.clipDBWithKeyGroupRange(
    db,
    states.map { it.columnFamilyHandle },
    KeyGroupRange.EMPTY_KEY_GROUP_RANGE,
    backend.keyGroupRange,
    
computeRequiredBytesInKeyGroupPrefix(runtimeContext.taskInfo.maxNumberOfParallelSubtasks),
    true,
)
{code}

This works, but it needs two reflective field reads and depends on internal 
classes. It also only empties the column families. They stay registered in the 
backend.

h3. Proposal

A supported way to drop keyed state that no longer has a descriptor, without 
stopping the job to rewrite a savepoint. Two possible shapes:
# An explicit API to drop a keyed state by name or descriptor.
# Extend {{ignore-unclaimed-state}} to state inside an operator (FLIP-359): 
column families restored from the checkpoint but not registered after 
{{open()}} are dropped.

On ForSt both can reuse existing code: {{dropColumnFamily}}, or 
{{clipDBWithKeyGroupRange}} with an empty target range as above.

Checkpoints taken after the restore should no longer reference the dropped 
state, and its files should be deleted once no retained checkpoint references 
them.

h3. Related

* FLINK-32658 / FLIP-359: same leak, proposed for heap and RocksDB only
* FLINK-10121: remove registered operator states
* FLINK-37686: needed for {{deleteFilesInRanges}} on restored (NOT_OWNED) files
* User ML thread: 
https://lists.apache.org/thread/s10jzzqb0xrgzcs741d2mfwbr90q87lf



--
This message was sent by Atlassian Jira
(v10.3.26#10030026)

Reply via email to