Conversation
| () -> { | ||
| validateTieringServiceRequest(tableId, tieredEpoch); | ||
| TieringState tieringState = tieringStates.get(tableId); | ||
| if (!isForceFinished |
There was a problem hiding this comment.
| if (!isForceFinished | |
| if (tieringState == TieringState.Scheduled) { | |
| // Completion reports are delivered at least once. Overlapping heartbeats may copy the | |
| // same finishedTables entry before the first response removes it, and a lost response | |
| // may also cause the report to be retried. The first report has already moved the table | |
| // to Scheduled, so ignore subsequent reports to preserve the recorded statistics and | |
| // avoid invalid state transitions. | |
| LOG.debug( | |
| "Ignore the duplicate tiering completion report for table {} at epoch {} " | |
| + "because the table is already in Scheduled state.", | |
| tableId, | |
| tieredEpoch); | |
| return; | |
| } |
| // for the same epoch as a successful no-op. | ||
| return; | ||
| } | ||
| if (tieringState != TieringState.Tiering) { |
There was a problem hiding this comment.
I think we can remove this
| } | ||
|
|
||
| @Test | ||
| void testDuplicateNormalFinishIsIdempotent() { |
There was a problem hiding this comment.
Could we simplify the regression coverage by extending the existing testFinishTableTieringReTriggerSchedule above instead of adding a separate full-lifecycle test? After the first successful finish, send the same completion again with different stats, then assert that the completion timestamp, duration, file size, record count, and original scheduling remain unchanged. The existing test can still advance to the next round and verify epoch 2.
With the proposed Scheduled no-op semantics, the initial-Scheduled half of testFinishTableTieringRequiresTieringState is no longer applicable; that test can be removed or reduced to only the remaining state behavior. Stale-epoch fencing is already covered by testTieringServiceTimeOutReTriggerPending, while the short repeated force-finish assertion can stay in the force-finish test. This should keep all important behavior covered while reducing the added test code substantially.
|
Thanks for the review, @luoyuxia. I’ve addressed all the comments:
|
Purpose
Linked issue: close #4406
Tiering completion reports are delivered with at-least-once semantics and may overlap while an earlier heartbeat is still in flight. A repeated normal completion for the same table and tiering epoch currently passes epoch validation, overwrites the previously recorded tiering result, and then attempts two invalid state transitions.
This change makes duplicate normal completion reports idempotent and ensures that completion eligibility is validated before tiering statistics are modified.
Brief change log
Tieringstate before updating tiering statistics.Tests
LakeTableTieringManagerTestTest command:
mvn -pl fluss-server -am \ -DskipITs \ -Dcheckstyle.skip=true \ -DfailIfNoTests=false \ -Dsurefire.failIfNoSpecifiedTests=false \ -Dtest=LakeTableTieringManagerTest \ testAPI and Format
No public API, RPC protocol, or storage format changes.
Documentation
No documentation changes are required because this is an internal server-side correctness fix.