1717
1818package org .apache .fluss .flink .tiering .source .enumerator ;
1919
20- import org .apache .flink .api .connector .source .ReaderInfo ;
21- import org .apache .flink .api .connector .source .SourceEvent ;
22- import org .apache .flink .api .connector .source .SplitEnumerator ;
23- import org .apache .flink .api .connector .source .SplitEnumeratorContext ;
24- import org .apache .flink .api .java .tuple .Tuple3 ;
25- import org .apache .flink .metrics .groups .SplitEnumeratorMetricGroup ;
26- import org .apache .flink .util .FlinkRuntimeException ;
2720import org .apache .fluss .annotation .VisibleForTesting ;
2821import org .apache .fluss .client .Connection ;
2922import org .apache .fluss .client .ConnectionFactory ;
4841import org .apache .fluss .rpc .messages .PbLakeTieringTableInfo ;
4942import org .apache .fluss .rpc .metrics .ClientMetricGroup ;
5043import org .apache .fluss .utils .MapUtils ;
44+
45+ import org .apache .flink .api .connector .source .ReaderInfo ;
46+ import org .apache .flink .api .connector .source .SourceEvent ;
47+ import org .apache .flink .api .connector .source .SplitEnumerator ;
48+ import org .apache .flink .api .connector .source .SplitEnumeratorContext ;
49+ import org .apache .flink .api .java .tuple .Tuple3 ;
50+ import org .apache .flink .metrics .groups .SplitEnumeratorMetricGroup ;
51+ import org .apache .flink .util .FlinkRuntimeException ;
5152import org .slf4j .Logger ;
5253import org .slf4j .LoggerFactory ;
5354
5455import javax .annotation .Nullable ;
56+
5557import java .io .IOException ;
5658import java .util .ArrayList ;
5759import java .util .Collections ;
@@ -102,7 +104,7 @@ public class TieringSourceEnumerator
102104
103105 private final Map <Long , Long > tieringTableEpochs ;
104106 private final Map <Long , Long > failedTableEpochs ;
105- private final Map <Long , Long > finishedTableEpochs ;
107+ private final Map <Long , TieringFinishState > finishedTables ;
106108 private final Set <Long > tieringReachMaxDurationsTables ;
107109
108110 // lazily instantiated
@@ -131,7 +133,7 @@ public TieringSourceEnumerator(
131133 this .pendingSplits = Collections .synchronizedList (new ArrayList <>());
132134 this .readersAwaitingSplit = Collections .synchronizedSet (new TreeSet <>());
133135 this .tieringTableEpochs = MapUtils .newConcurrentHashMap ();
134- this .finishedTableEpochs = MapUtils .newConcurrentHashMap ();
136+ this .finishedTables = MapUtils .newConcurrentHashMap ();
135137 this .failedTableEpochs = MapUtils .newConcurrentHashMap ();
136138 this .tieringReachMaxDurationsTables = Collections .synchronizedSet (new TreeSet <>());
137139 }
@@ -252,7 +254,9 @@ public void handleSourceEvent(int subtaskId, SourceEvent sourceEvent) {
252254 "The finished table {} is not in tiering table, won't report it to Fluss to mark as finished." ,
253255 finishedTableId );
254256 } else {
255- finishedTableEpochs .put (finishedTableId , tieringEpoch );
257+ boolean isForceComplete = tieringReachMaxDurationsTables .remove (finishedTableId );
258+ finishedTables .put (
259+ finishedTableId , TieringFinishState .from (tieringEpoch , isForceComplete ));
256260 }
257261 }
258262
@@ -274,7 +278,7 @@ public void handleSourceEvent(int subtaskId, SourceEvent sourceEvent) {
274278 }
275279 }
276280
277- if (!finishedTableEpochs .isEmpty () || !failedTableEpochs .isEmpty ()) {
281+ if (!finishedTables .isEmpty () || !failedTableEpochs .isEmpty ()) {
278282 // call one round of heartbeat to notify table has been finished or failed
279283 this .context .callAsync (
280284 this ::requestTieringTableSplitsViaHeartBeat , this ::generateAndAssignSplits );
@@ -288,6 +292,7 @@ private void handleSourceReaderFailOver() {
288292 // we need to make all as failed
289293 failedTableEpochs .putAll (new HashMap <>(tieringTableEpochs ));
290294 tieringTableEpochs .clear ();
295+ tieringReachMaxDurationsTables .clear ();
291296 // also clean all pending splits since we mark all as failed
292297 pendingSplits .clear ();
293298 if (!failedTableEpochs .isEmpty ()) {
@@ -362,13 +367,13 @@ private void assignSplits() {
362367 if (closed ) {
363368 return null ;
364369 }
365- Map <Long , Long > currentFinishedTableEpochs = new HashMap <>(this .finishedTableEpochs );
370+ Map <Long , TieringFinishState > currentFinishedTables = new HashMap <>(this .finishedTables );
366371 Map <Long , Long > currentFailedTableEpochs = new HashMap <>(this .failedTableEpochs );
367372 LakeTieringHeartbeatRequest tieringHeartbeatRequest =
368373 tieringTableHeartBeat (
369374 basicHeartBeat (),
370375 this .tieringTableEpochs ,
371- currentFinishedTableEpochs ,
376+ currentFinishedTables ,
372377 currentFailedTableEpochs ,
373378 this .flussCoordinatorEpoch );
374379
@@ -397,9 +402,9 @@ private void assignSplits() {
397402 waitHeartbeatResponse (coordinatorGateway .lakeTieringHeartbeat (tieringHeartbeatRequest ));
398403 }
399404
400- // if come to here, we can remove currentFinishedTableEpochs /failedTableEpochs to avoid send
405+ // if come to here, we can remove currentFinishedTables /failedTableEpochs to avoid send
401406 // in next round
402- currentFinishedTableEpochs .forEach (finishedTableEpochs ::remove );
407+ currentFinishedTables .forEach (finishedTables ::remove );
403408 currentFailedTableEpochs .forEach (failedTableEpochs ::remove );
404409 return lakeTieringInfo ;
405410 }
@@ -428,7 +433,7 @@ private void generateTieringSplits(Tuple3<Long, Long, TablePath> tieringTable)
428433 LOG .info (
429434 "Generate Tiering splits for table {} is empty, no need to tier data." ,
430435 tieringTable .f2 .getTableName ());
431- finishedTableEpochs .put (tieringTable .f0 , tieringTable .f1 );
436+ finishedTables .put (tieringTable .f0 , TieringFinishState . from ( tieringTable .f1 ) );
432437 } else {
433438 tieringTableEpochs .put (tieringTable .f0 , tieringTable .f1 );
434439 pendingSplits .addAll (tieringSplits );
@@ -537,16 +542,28 @@ static LakeTieringHeartbeatRequest heartBeatWithRequestNewTieringTable(
537542 static LakeTieringHeartbeatRequest tieringTableHeartBeat (
538543 LakeTieringHeartbeatRequest heartbeatRequest ,
539544 Map <Long , Long > tieringTableEpochs ,
540- Map <Long , Long > finishedTableEpochs ,
545+ Map <Long , TieringFinishState > finishedTables ,
541546 Map <Long , Long > failedTableEpochs ,
542547 int coordinatorEpoch ) {
543548 if (!tieringTableEpochs .isEmpty ()) {
544549 heartbeatRequest .addAllTieringTables (
545550 toPbHeartbeatReqForTable (tieringTableEpochs , coordinatorEpoch ));
546551 }
547- if (!finishedTableEpochs .isEmpty ()) {
552+ if (!finishedTables .isEmpty ()) {
553+ Map <Long , Long > finishTieringEpochs = new HashMap <>();
554+ Set <Long > forceFinishedTables = new HashSet <>();
555+ finishedTables .forEach (
556+ (tableId , tieringFinishState ) -> {
557+ finishTieringEpochs .put (tableId , tieringFinishState .tieringEpoch );
558+ if (tieringFinishState .isForceToFinish ) {
559+ forceFinishedTables .add (tableId );
560+ }
561+ });
548562 heartbeatRequest .addAllFinishedTables (
549- toPbHeartbeatReqForTable (finishedTableEpochs , coordinatorEpoch ));
563+ toPbHeartbeatReqForTable (finishTieringEpochs , coordinatorEpoch ));
564+ for (long forceFinishedTableId : forceFinishedTables ) {
565+ heartbeatRequest .addForceFinishedTable (forceFinishedTableId );
566+ }
550567 }
551568 // add failed tiering table to heart beat request
552569 return failedTableHeartBeat (heartbeatRequest , failedTableEpochs , coordinatorEpoch );
@@ -590,4 +607,22 @@ static LakeTieringHeartbeatResponse waitHeartbeatResponse(
590607 }
591608 }
592609 }
610+
611+ private static class TieringFinishState {
612+ long tieringEpoch ;
613+ boolean isForceToFinish ;
614+
615+ public static TieringFinishState from (long tieringEpoch ) {
616+ return new TieringFinishState (tieringEpoch , false );
617+ }
618+
619+ public static TieringFinishState from (long tieringEpoch , boolean isForceToFinish ) {
620+ return new TieringFinishState (tieringEpoch , isForceToFinish );
621+ }
622+
623+ private TieringFinishState (long tieringEpoch , boolean isForceToFinish ) {
624+ this .tieringEpoch = tieringEpoch ;
625+ this .isForceToFinish = isForceToFinish ;
626+ }
627+ }
593628}
0 commit comments