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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants