Skip to content

[FLINK-40171][table-runtime] Emit and retract early-fire results in the interval join operator - #4

Draft
weiqingy wants to merge 7 commits into
FLINK-36953-pr3-changelogfrom
FLINK-36953-pr4-runtime
Draft

[FLINK-40171][table-runtime] Emit and retract early-fire results in the interval join operator#4
weiqingy wants to merge 7 commits into
FLINK-36953-pr3-changelogfrom
FLINK-36953-pr4-runtime

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-3. Landing order: PR-1a → PR-1b → PR-2 → PR-3 → PR-4 (this) → PR-5 → PR-6 → PR-7.

What is the purpose of the change

Implements the runtime behavior for the EARLY_FIRE hint on an interval join. An unmatched outer row is emitted speculatively with a null-padded counterpart after the configured delay; if a real match later arrives within the window, the speculative row is retracted and corrected. This covers the natural time-domain pairings (event-time join with event-time delay, processing-time join with processing-time delay).

Brief change log

  • New operator constructor parameter earlyFireDelay and bookkeeping MapState tracking whether a row has already early-fired.
  • Schedule an early-fire timer for unmatched outer rows; on timer, emit the speculative padded row and set the bit.
  • On a later match, retract the padded row and emit the corrected join result.
  • StreamExecIntervalJoin unboxes and passes the delay to the operator.

Verifying this change

This change added tests and can be verified as follows:

  • Added harness tests in RowTimeIntervalJoinTest / ProcTimeIntervalJoinTest asserting the speculative +I then -D/-U + +U on match, for left/right/full outer joins.

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): no
  • The serializers: no
  • The runtime per-record code paths (performance sensitive): yes — interval join operator record path (behavior gated on the hint; default off)
  • Anything that affects deployment or recovery: no
  • The S3 file system connector: no

Documentation

  • Does this pull request introduce a new feature? no (runtime for the FLIP-497 hint)
  • If yes, how is the feature documented? not applicable

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

Generated-by: Claude Code (Anthropic)

…dation

Register the EARLY_FIRE join hint and its typed options
(EarlyFireJoinHintOptions: delay, time_mode) with a key-value option
checker, and wire the query-hint propagation touchpoints. Exclude
EARLY_FIRE from the generic join-hint test coverage and config-docs
generation, since it is a key-value hint validated on its own.

The hint is recognized and validated here but not yet consumed by any
rule; threading it into the interval join follows in a separate change.
@weiqingy
weiqingy force-pushed the FLINK-36953-pr3-changelog branch from f6163da to 16ae7d2 Compare July 18, 2026 22:12
@weiqingy
weiqingy force-pushed the FLINK-36953-pr4-runtime branch from a56a787 to fcb8e67 Compare July 18, 2026 22:12
@weiqingy weiqingy changed the title [FLINK-36953][table-runtime] Emit and retract early-fire results in the interval join operator [FLINK-40171][table-runtime] Emit and retract early-fire results in the interval join operator Jul 18, 2026
…time-mode

Flink option keys use hyphens (e.g. output-mode, fixed-delay); rename the
EARLY_FIRE hint's time_mode option key to time-mode to match, and update
the affected tests.
@weiqingy
weiqingy force-pushed the FLINK-36953-pr4-runtime branch from fcb8e67 to 72e92e5 Compare July 21, 2026 02:17
@weiqingy
weiqingy force-pushed the FLINK-36953-pr3-changelog branch from 16ae7d2 to 17d607b Compare July 21, 2026 02:17
weiqingy and others added 5 commits July 20, 2026 21:25
…idation tests

The runtime uses delay.toMillis(), so a sub-millisecond delay truncates to
zero. Make the contract explicit: require at least 1 millisecond in the DELAY
description and the checker error message. Add coverage for a sub-millisecond
delay, list-style options (only key-value is supported), and case-insensitive
hint-name capitalization that preserves the key-value options.
Read the EARLY_FIRE hint in StreamPhysicalIntervalJoinRule and thread
its delay and time mode through StreamPhysicalIntervalJoin into
StreamExecIntervalJoin as NON_NULL JSON fields. Resolve the effective
time mode from the join's time domain, reject row-time triggering on a
processing-time join, and reject (for now) processing-time triggering on
an event-time join. The operator receives the parameters but ignores
them; runtime behavior follows in a later change.
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.
…fire interval join

With the EARLY_FIRE hint, an outer interval join speculatively emits a padded
unmatched row after the delay and corrects it when a match later arrives, so it
no longer produces insert-only changes. Teach FlinkChangelogModeInferenceProgram
to reflect this.

Split StreamPhysicalIntervalJoin into its own ModifyKindSet arm: its children
still consume insert-only, but the node provides INSERT and, when the hint makes
it update-producing, UPDATE. A new produceEarlyFireUpdates accessor gates that on
the hint being set, the join being outer, and a non-negative window span, so the
hint stays inert for inner joins and negative-window joins (which only ever emit
inserts). The interval join keeps its place in the UpdateKind and DeleteKind arms.

When such a join feeds an insert-only downstream, planning fails with a tailored
error that names the hint, rather than the generic "doesn't support consuming
update changes" message. Runtime behavior is unchanged; the operator still
ignores the hint.
…val join operator

Wire the EARLY_FIRE delay into the interval join operator so an outer join
speculatively emits its padded unmatched row after the delay and corrects it
when a real match arrives. Covers the natural timer pairings: a row-time join
fires on event time, a processing-time join fires on processing time.
Processing-time triggering on a row-time join stays rejected at planning.

When an unmatched outer row is cached, the operator registers an early-fire
timer at rowTime + delay. On that timer it emits the padded row as an INSERT
and records that it fired. When the row later matches, it retracts the padded
row as UPDATE_BEFORE and emits the matched row as UPDATE_AFTER, matching the
update-producing changelog mode inferred for the node. The retraction is tied
to the one-time matched-and-emitted flip, so a row that matches several times
emits a single correction followed by ordinary inserts.

The already-fired marker is a new per-side MapState<Long, List<Boolean>> kept
positionally aligned with the existing row cache, rather than widening the
cache tuple, so the cache serializer is unchanged and old savepoints restore
the new state empty. The marker is the single gate that keeps a row padded
exactly once when the delay is at or beyond the window span. All early-fire
work is gated on the hint being set, an outer join, and a non-negative window,
so a plain interval join is unchanged and allocates nothing new.

EmitAwareCollector carries the changelog stamping so IntervalJoinFunction stays
changelog-agnostic, and every padded or matched emit stamps its RowKind
explicitly to avoid leaking a kind onto a reused row.
@weiqingy
weiqingy force-pushed the FLINK-36953-pr4-runtime branch from 72e92e5 to ebe6e95 Compare July 21, 2026 04:43
@weiqingy
weiqingy force-pushed the FLINK-36953-pr3-changelog branch from 17d607b to 9dbe90d Compare July 21, 2026 04:43
@weiqingy
weiqingy force-pushed the FLINK-36953-pr3-changelog branch from 9dbe90d to 8f7448f Compare August 2, 2026 22:42
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.

1 participant