Skip to content

[FLINK-40173][table-planner] Add restore coverage for early-fire interval join - #29045

Draft
weiqingy wants to merge 2 commits into
apache:masterfrom
weiqingy:FLINK-36953-pr6-serde
Draft

[FLINK-40173][table-planner] Add restore coverage for early-fire interval join#29045
weiqingy wants to merge 2 commits into
apache:masterfrom
weiqingy:FLINK-36953-pr6-serde

Conversation

@weiqingy

Copy link
Copy Markdown
Contributor

Part of the FLIP-497 implementation stack under umbrella FLINK-36953. Landing order:

Step Sub-task Scope
PR-1a FLINK-40167 EARLY_FIRE hint surface + option validation (#28353, merged)
PR-1b FLINK-40168 Thread the hint into the interval join (#28796, merged)
PR-2 FLINK-40169 target option (#28827, merged)
PR-3 FLINK-40170 Update-producing changelog mode + insert-only guard (#28877, merged)
PR-4 FLINK-40171 Runtime early-fire emit + retraction (#28952, merged)
PR-5 FLINK-40172 Processing-time early fire on an event-time join (#28953, in review)
PR-6 (this PR) FLINK-40173 State restore coverage
PR-7 FLINK-40174 User-facing documentation

Opened as a draft because it is stacked on #28953, which is in review. Until that merges, the commit list and diff here also carry PR-5's commit. Once #28953 merges I will rebase onto master, leaving only this PR's change, and take it out of draft.

What is the purpose of the change

Adds end-to-end restore coverage for the early-fire interval join: a compiled plan plus a savepoint, restored and run. The two early-fire time modes keep different operator state, so there is one program for each.

Brief change log

  • INTERVAL_JOIN_EARLY_FIRE, a row-time program covering the fired bookkeeping restored from a savepoint. A row padded before the savepoint is matched after it, so the restored bit is what turns the match into a -U/+U correction rather than a plain +I.
  • INTERVAL_JOIN_PROC_TIME_EARLY_FIRE, a processing-time program covering the cross-domain schedule state, which only exists in that mode.
  • The processing-time program lives in its own IntervalJoinProcTimeEarlyFireRestoreTest with an INFINITE after-restore source and no after-restore input, following GroupWindowAggregateProcTimeRestoreTest. With no further input there is no MAX_WATERMARK and so no cleanup path, which keeps the result deterministic: the single emitted row can only come from the restored schedule. A finite program would race the restored timer against the first record.
  • It sets its source options explicitly because RestoreTestBase.enablePerRecordWatermarks matches WATERMARK FOR while the interval-join schema spells it WATERMARK for, so the automatic path has never applied to these programs.

Verifying this change

This change added tests and can be verified as follows:

  • Both programs run plan plus savepoint restore. Renaming the schedule state descriptor makes the processing-time program fail with an empty result, so the assertion depends on the restored state rather than on the value being re-derived.

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): no
  • Anything that affects deployment or recovery: no (test-only coverage of restore)
  • The S3 file system connector: no

Documentation

  • Does this pull request introduce a new feature? no (test coverage 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)

weiqingy and others added 2 commits August 29, 2026 15:58
…row-time interval join

Add the cross-domain timer combination the previous commit left out: an
event-time interval join with EARLY_FIRE('time_mode'='proctime') now fires its
speculative pads on the wall clock while keeping its event-time cleanup. The
temporary "not yet supported" rejection in the planner rule is removed; the
row-time-on-processing-time rejection is retained.

onTimer distinguishes the two timer kinds by OnTimerContext.timeDomain(): in
the cross-domain case early-fire timers are processing-time and cleanup timers
are event-time, so a processing-time firing runs early fire and returns while
an event-time firing runs cleanup only. The discrimination is gated on a new
cross-domain flag, so the natural pairings keep the previous timestamp - delay
recovery where early fire and cleanup share a domain.

A processing-time firing timestamp cannot be mapped back to an event-time cache
bucket arithmetically, so a per-side MapState<Long, List<Long>> keyed by firing
processing-time records the event-time bucket keys due to fire then. It is
allocated only in the cross-domain case and reuses the existing per-bucket emit
and positional fired bit, so the retract-and-correct path is shared. Every
scheduled firing time fires and removes its own entry, and a bucket already
cleaned by event-time expiry makes the firing a no-op, so nothing accumulates.

The schedule is value-typed and order-preserving and processing-time timers are
checkpointed, so a timer pending at snapshot fires after restore against the
restored schedule and fired bits and emits at most the not-yet-emitted pad.
Harness tests cover the wall-clock trigger without watermark advance, a snapshot
before the timer fires, and a snapshot after the pad is emitted.
…rval join

Add an INTERVAL_JOIN_EARLY_FIRE restore test program with its plan and
savepoint fixtures, and register it in IntervalJoinRestoreTest, exercising
end-to-end plan and savepoint restore for the early-fire interval join.

Cover both early-fire time modes. The row-time program exercises the fired
bookkeeping restored from a savepoint; a second program with a processing-time
delay covers the cross-domain schedule state, which only exists in that mode.
The processing-time program restores with no further input, so its only output
can come from the restored schedule.
@flinkbot

flinkbot commented Aug 30, 2026

Copy link
Copy Markdown
Collaborator

CI report:

Bot commands The @flinkbot bot supports the following commands:
  • @flinkbot run azure re-run the last Azure build
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

2 participants