Bonnie Varghese created FLINK-41310:
---------------------------------------

             Summary:  BatchExecAdaptiveJoin sizes the external buffer from the 
runtime config instead of the compiled plan
                 Key: FLINK-41310
                 URL: https://issues.apache.org/jira/browse/FLINK-41310
             Project: Flink
          Issue Type: Bug
          Components: Table SQL / Planner
    Affects Versions: 2.5.0
            Reporter: Bonnie Varghese
            Assignee: Bonnie Varghese
             Fix For: 2.5.0


When a batch job runs from a compiled plan, \{{BatchExecAdaptiveJoin}} reads 
the external buffer size and the managed memory budget from two different 
configs.

* At translation time, \{{translateToPlanInternal}} computes \{{managedMemory}} 
via \{{JoinUtil.getManagedMemory}} from the node's \{{ExecNodeConfig}}. For a 
compiled plan, that config is the one persisted in the plan. The plan always 
persists \{{table.exec.resource.hash-join.memory}}, 
\{{table.exec.resource.sort.memory}} and 
\{{table.exec.resource.external-buffer-memory}}, even when they are set to 
their defaults.
* At runtime, \{{PostProcessAdaptiveJoinStrategy}} builds the actual join 
operator with \{{context.getStreamGraph().getConfiguration()}}. That is the 
config of the session that compiled the job, not the persisted plan config. 
\{{HashJoinOperatorUtil}} and \{{SorMergeJoinOperatorUtil}} then compute the 
external buffer fraction as:

{code:java}
config.get(TABLE_EXEC_RESOURCE_EXTERNAL_BUFFER_MEMORY).getBytes() / 
managedMemory
{code}

If the session that compiles the job sets 
\{{table.exec.resource.external-buffer-memory}} to a different value than the 
session that compiled the plan, the two values don't match:
* With a higher value, the fraction can exceed 1, and 
\{{SortMergeJoinFunction#open}} fails with "Memory size is too small". With the 
defaults the budget is max(128 MB, 10 MB + 2 * 128 MB) = 266 MB, so a job 
compiled with the buffer set to 300 MB fails.
* With a smaller difference the job doesn't fail, but the buffer quietly takes 
memory from the sorters.

{\{BatchExecHashJoin}} and \{{BatchExecSortMergeJoin}} are not affected, 
because they build their operators at translation time and read both values 
from the same \{{ExecNodeConfig}}. The adaptive join is the only join that 
postpones building the operator to runtime. This only became reachable once 
\{{BatchExecAdaptiveJoin}} could be serialized into a compiled plan 
(FLINK-41263).

*Proposed fix*
Read \{{table.exec.resource.external-buffer-memory}} from the 
\{{ExecNodeConfig}} in \{{BatchExecAdaptiveJoin#translateToPlanInternal}}, pass 
it into \{{AdaptiveJoinOperatorGenerator}} next to \{{managedMemory}}, and use 
it in place of the runtime config value. The budget and the buffer then always 
come from the same persisted config. The compiled plan JSON doesn't change, 
because the generator is serialized into the operator factory, not the plan.

*Test*
Compile a plan with an adaptive join (converted from a sort merge join), raise 
\{{table.exec.resource.external-buffer-memory}} in the session above the 
persisted budget, then load and execute the plan. The job should succeed and 
produce the expected results. It fails without the fix.



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

Reply via email to