Skip to content

[FLINK-40169][table] Add target option to the EARLY_FIRE hint - #2

Draft
weiqingy wants to merge 51 commits into
FLINK-36953-pr1b-threadfrom
FLINK-36953-pr2-target
Draft

[FLINK-40169][table] Add target option to the EARLY_FIRE hint#2
weiqingy wants to merge 51 commits into
FLINK-36953-pr1b-threadfrom
FLINK-36953-pr2-target

Conversation

@weiqingy

@weiqingy weiqingy commented Jul 18, 2026

Copy link
Copy Markdown
Owner

Part of the FLIP-497 stack under umbrella FLINK-36953. Stacked on PR-1b. Landing order: PR-1a → PR-1b → PR-2 (this) → PR-3 → PR-4 → PR-5 → PR-6 → PR-7.

What is the purpose of the change

Adds an optional target option to the EARLY_FIRE hint so a hint can be explicitly scoped to a single operator kind. This is a forward-compatibility guard: it keeps a bare EARLY_FIRE hint from silently expanding to other operators if any of them honor the hint in the future.

Brief change log

  • Add EarlyFireJoinHintOptions.TARGET (optional stringType) and the INTERVAL_JOIN constant.
  • EARLY_FIRE KV option checker validates target ∈ {interval_join}; any other value fails planning.
  • StreamPhysicalIntervalJoinRule applies the hint only when it targets the interval join; an omitted target is equivalent to interval_join, so existing hints keep their meaning.

Verifying this change

This change added tests and can be verified as follows:

  • Added IntervalJoinTest cases: an explicit target='interval_join' produces the same plan as the default form, and an unsupported target value fails planning.

Does this pull request potentially affect one of the following parts:

  • Dependencies (does it add or upgrade a dependency): no
  • The public API, i.e., is any changed class annotated with @Public(Evolving): yes — new option on @PublicEvolving EarlyFireJoinHintOptions
  • The serializers: no
  • The runtime per-record code paths (performance sensitive): no
  • Anything that affects deployment or recovery: no
  • The S3 file system connector: no

Documentation

  • Does this pull request introduce a new feature? yes (an option on the FLIP-497 hint)
  • If yes, how is the feature documented? Documented in the docs PR at the end of this stack (PR-7).

Was generative AI tooling used to co-author this PR?
  • Yes (please specify the tool below)

Generated-by: Claude Code (Anthropic)

@weiqingy
weiqingy force-pushed the FLINK-36953-pr2-target branch from 0b76a4b to dc1e210 Compare July 18, 2026 22:12
@weiqingy
weiqingy changed the base branch from FLINK-36953-impl to FLINK-36953-pr1b-thread July 18, 2026 22:14
@weiqingy weiqingy changed the title [FLINK-36953][table] Add target option to the EARLY_FIRE hint [FLINK-40169][table] Add target option to the EARLY_FIRE hint Jul 18, 2026
@weiqingy
weiqingy force-pushed the FLINK-36953-pr1b-thread branch from e846e4e to 7dc4d49 Compare July 21, 2026 02:17
@weiqingy
weiqingy force-pushed the FLINK-36953-pr2-target branch 2 times, most recently from 2d8840b to 8000ad1 Compare July 21, 2026 04:43
@weiqingy
weiqingy force-pushed the FLINK-36953-pr1b-thread branch 5 times, most recently from 647116f to a856401 Compare July 25, 2026 02:10
snuyanzin and others added 2 commits July 25, 2026 22:26
as it requires minimum jdk17

This reverts commit 4e99512.
GHA pipelines use some of the assets from tools/azure-pipelines

This commit moves them into tools/ci to reflect that they are not
unique to the AZP builds, and are common across both.

Signed-off-by: Dale Lane <dale.lane@uk.ibm.com>
@weiqingy
weiqingy force-pushed the FLINK-36953-pr2-target branch from 8000ad1 to 0ef163a Compare July 27, 2026 02:41
snuyanzin and others added 15 commits July 27, 2026 07:06
…ght generate runtime code with useless array copy
Refresh user-facing doc links that broke after source relocations and
external site restructuring. All targets verified reachable (HTTP 200
or file present on master).

gh_link source references:
- SourceFunction, SinkFunction, Trigger -> relocated legacy paths in
  flink-runtime.
- WithPre/WithPostCommitTopology -> renamed Supports{Pre,Post}CommitTopology
  in flink-runtime.

External links:
- Avro schema-resolution spec, Curator error handling, FLIP-187 title,
  PyFlink TableEnvironment API doc, Apache Superset Hive guide.
- Gradle Shadow issue johnrengelman -> GradleUp.
- Debezium reference 1.2/1.3 -> stable (mysql events anchor updated).
…aFrame API

Generated-by: OpenAI Codex (GPT-5.6 Sol)

This closes apache#28797.
…_OP and a barrier-inserting in-memory implementation

New RecoveryCheckpointTrigger (checkpoint.channel): void
snapshotAndInsertBarriers(long checkpointId) -- narrow signature, widened to
return a snapshot reader when the spilling backend lands; NO_OP singleton
(no-op); NOT_READY singleton (throws
CheckpointException(CHECKPOINT_DECLINED_TASK_NOT_READY) -- transient, the
coordinator retries).

New transitional in-memory implementation InMemoryRecoveryCheckpointTrigger:
holds the task's List<RecoverableInputChannel>; snapshotAndInsertBarriers =
forEach(ch -> ch.insertRecoveryCheckpointBarrierIfInRecovery(cpId)). The
javadoc states why no snapshot exists (one-shot push means no undrained
residue) and that the disk drainer replaces it. Deleted when the spilling
backend lands.

Unit tests for all three implementations.

Co-authored-by: Roman Khachatryan <khachatryan.roman@gmail.com>
…ough the recovery trigger

ChannelState gains a RecoveryCheckpointTrigger (the legacy 1-arg ctor defaults
to NO_OP); new onCheckpointStartedForAllInputs(CheckpointBarrier): (1)
trigger.snapshotAndInsertBarriers(cpId); (2) for (input : inputs)
input.checkpointStarted(barrier). CheckpointException is rethrown as-is
(routes to checkpoint abort, not task failure); other IOException via
rethrowIOException. (Step 3 -- spilled-slice replay through the channel-state
writer -- is added when the spilling backend lands.)

AlternatingCollectingBarriers and AlternatingWaitingForFirstBarrierUnaligned:
replace the inline per-input checkpointStarted loop with
state.onCheckpointStartedForAllInputs(...) (behaviorally inert with NO_OP).

Tests: ChannelStateTest (2-step scope),
AlternatingCollectingBarriersDispatchHookTest,
AlternatingWaitingForFirstBarrierUnalignedDispatchHookTest.
… and the StreamTask lifecycle

InputProcessorUtil.createCheckpointBarrierHandler: overload taking a
RecoveryCheckpointTrigger (the old signature is preserved as a NO_OP
delegator); SingleCheckpointBarrierHandler.unaligned/alternating gain the
trigger param (aligned keeps the NO_OP default through ChannelState's 1-arg
ctor); OneInputStreamTask/TwoInputStreamTask/MultipleInputStreamTask pass
StreamTask.getRecoveryCheckpointTrigger(). (The channel-state writer is
threaded through the same seams when the spilling backend lands.)

StreamTask: recoveryCheckpointTrigger field (starts NOT_READY) +
mailbox-thread-asserting getter lambda; all asynchronous mutations via
setRecoveryCheckpointTrigger (a mailbox mail). Lifecycle inside
recoverChannelsWithCheckpointing: NOT_READY before/during filtering
(checkpoints declined as task-not-ready; transient, the coordinator retries)
-> install the in-memory barrier-inserting trigger at conversion, composing on
requestPartitions' returned List<RecoverableInputChannel> -> swap to NO_OP
when completeAll(gates' stateConsumedFutures) completes (gate on the futures,
not on push completion; the mailbox-mail gap is safe because a
barrier-inserting trigger with no in-recovery channels behaves as NO_OP).
recoverChannelsWithoutCheckpointing and the empty-input-gates short-circuit go
straight to NO_OP.

Also fix the transitional conversion push's sentinel timing: the
EndOfFetchedChannelStateEvent sentinel is no longer appended inside
toInputChannelInRecovery() (where it becomes consumable before the upstream
connection exists, letting a spurious post-recovery poll hit a LocalInputChannel
without a subpartition view: "Queried for a buffer before requesting the
subpartition"). Instead the recovery chain appends it via
finishRecoveredBufferDelivery() on the channelIOExecutor after partitions are
requested -- the method waits for upstream readiness, restoring the invariant
the disk drainer also relies on, and mirroring where the drainer will run.

Tests: TestBarrierHandlerFactory adaptation; StreamTask trigger-lifecycle
source-level invariants (transitional, replaced with the disk drainer wiring
when the spilling backend lands); RecoveredInputChannelTest push-conversion
case adapted to the sentinel timing.
…able filtering ITCase

TestStreamEnvironment: restore randomize(conf,
CHECKPOINTING_DURING_RECOVERY_ENABLED, true, false), closing the transitional
randomization window opened when the v1 conversion-migration path was retired.
Re-enable RecoveredStateFilteringLargeRecordITCase.

From here on the randomized ITCase fleet runs flag-on ~50% against the
in-memory backend (same memory profile as base v1, which ran the same
randomization with the same heap fallback). The spilling PRs must keep the
fleet green -- this is the acceptance bar for "lightweight backend
replacement".
…ry twice

testSavepointDeepCopy listed savepointPath1 for both stateFiles1 and
stateFiles2, so the copied-files assertion compared savepoint1's
directory with itself and savepoint2's directory was never examined at
all. Point stateFiles2 at savepointPath2, as the variable name, the
assertion messages, and the test's documented steps always intended.

The mix-up was introduced when the getFileNamesInDirectory helper was
extracted (f125067); before that, both checks listed savepointPath2.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…from native savepoint

The first incremental checkpoint after a CLAIM-mode restore from a native
savepoint reuses the savepoint's SST files as RelativeFileStateHandles. The
metadata serializer stored only their relative path, so on restore they were
resolved against the new checkpoint's exclusive directory and could no longer
be found.

The serializer now knows the exclusive directory of the checkpoint being
written (CheckpointMetadataOutputStream#getExclusiveCheckpointDir, passed down
as a non-null SerializationContext) and keeps the compact relative encoding
only for handles whose file actually lives in that directory; a foreign handle
(a reused savepoint SST) is persisted with its absolute path using the
pre-existing FileStateHandle encoding. The wire format and the metadata version
are unchanged. The state processor API keeps the unconditional relative
encoding via the explicit Checkpoints#storeCheckpointMetadataWithoutExclusiveDir,
because its deep copy places every referenced file next to the new metadata.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Samrat002 and others added 27 commits July 30, 2026 10:52
…patible servers that do not support AWS checksum-validation
…ITCase.testRestoreAfterSomeTasksFinished (apache#28800)

There was traced the flakiness to task finished after the checkpoint plan was calculated
but before triggerCheckpoint. The task is already removed from TaskExecutor#taskSlotTable
So TaskExecutor#triggerCheckpoint fails the checkpoint with error
'TaskManager received a checkpoint request for unknown task <>'.

Production systems are expected to tolerate an occasional checkpoint failure
So we can address the flakiness without changes this known limitation for
tasks finished mid checkpoint.

the test provisions 2 sources passA that finishes quickly and passB that blocks forever
and non-deterministically waits for at least one of passA subtasks to finish, which introduces
the race.
The fix here makes CheckpointAfterAllTasksFinishedITCase.testRestoreAfterSomeTasksFinished
wait for all subtasks of passA to finish before triggering savepoint, to avoid the race
but still achieve the test goal with passB subtasks still locking.
Introduce JobMdcRegistry, a process-wide registry mapping JobID to an
enriched MDC context built from job configuration. Add MdcOptions with
the mdc.job-configuration-to-mdc-keys config option (@PublicEvolving).
Wire in mdc enrichment on the job/task submission paths.

Generated-by: Claude Code
…estore from a NATIVE savepoint

Since FLINK-39964, the first incremental checkpoint(s) taken after a
CLAIM-mode restore from a NATIVE savepoint reference the reused savepoint
files by their absolute location. Extend the CLAIM-mode note on the
savepoints page (EN and ZH): such checkpoints are neither self-contained
nor relocatable (consistent with incremental checkpoints in general), and
the savepoint directory remains referenced, with its files' lifecycle
managed by Flink, until every checkpoint reusing its files has been
subsumed.

Generated-by: Claude Fable 5
Introduce JobMdcRegistry, a process-wide registry mapping JobID to an
enriched MDC context built from job configuration. Add MdcOptions with
the mdc.job-configuration-to-mdc-keys config option (@PublicEvolving).
Wire in mdc enrichment on the job/task submission paths.

Generated-by: Claude Code
Generated-by: Claude Code
(cherry picked from commit ef6633f)
…of ForSt transfer threads (apache#28373)

---------

Co-authored-by: Purushottam Sinha <sinhapurushottam911@gmail.com>
… number of ForSt transfer threads (apache#28373)"

This reverts commit 01a5a7f.
…E`/`JSON_QUERY` calls when the owning call is skipped because of `NULL` or not taken branch
…ERIALIZED TABLE

Persisted columns of a materialized table have to be produced by its definition query, and CREATE OR ALTER enforces that through validatePersistedColumnsUsedByQuery while a plain CREATE only checked physical columns. A CREATE declaring a non-virtual metadata column that the query does not project was therefore accepted, and the mismatch only surfaced when the refresh pipeline compiled the insert, whose consumed row type contains the persisted metadata column.

Both statements share the validation now, so the DDL is rejected up front, and the error message names the statement it originates from. The test fixture for materialized tables with metadata columns projects its persisted column, which makes dropping that column report that it is used in the query rather than that persisted columns cannot be dropped; the latter stays covered by the query-evolution cases.

Generated-by: Claude Opus 5
Offload the dump to ioExecutor in both TaskExecutor#requestThreadDump
and Dispatcher#requestThreadDump via CompletableFuture.supplyAsync,
matching the pattern already used by other heavy TE handlers.
…nections

Co-authored-by: Roman Khachatryan <khachatryan.roman@gmail.com>
Add an optional `target` option to the EARLY_FIRE join hint. Only
`interval_join` is accepted today; any other value fails planning. An
omitted target is equivalent to `interval_join`, so existing hints keep
their meaning.

`target` scopes the hint to a single operator kind. The interval-join
rule consumes the hint only when it targets the interval join and leaves
a hint aimed at another operator kind untouched, so an untargeted hint
never silently expands its scope.
@weiqingy
weiqingy force-pushed the FLINK-36953-pr2-target branch from 0ef163a to 3b14d56 Compare August 2, 2026 22:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.