1717
1818package org .apache .fluss .flink .tiering .source .enumerator ;
1919
20+ import org .apache .flink .api .connector .source .SourceEvent ;
21+ import org .apache .flink .api .connector .source .SplitEnumerator ;
22+ import org .apache .flink .api .connector .source .SplitEnumeratorContext ;
23+ import org .apache .flink .api .java .tuple .Tuple3 ;
24+ import org .apache .flink .metrics .groups .SplitEnumeratorMetricGroup ;
25+ import org .apache .flink .util .FlinkRuntimeException ;
2026import org .apache .fluss .annotation .VisibleForTesting ;
2127import org .apache .fluss .client .Connection ;
2228import org .apache .fluss .client .ConnectionFactory ;
2733import org .apache .fluss .flink .tiering .event .FailedTieringEvent ;
2834import org .apache .fluss .flink .tiering .event .FinishedTieringEvent ;
2935import org .apache .fluss .flink .tiering .event .TieringFailOverEvent ;
36+ import org .apache .fluss .flink .tiering .event .TieringTimeoutEvent ;
3037import org .apache .fluss .flink .tiering .source .split .TieringSplit ;
3138import org .apache .fluss .flink .tiering .source .split .TieringSplitGenerator ;
3239import org .apache .fluss .flink .tiering .source .state .TieringSourceEnumeratorState ;
4047import org .apache .fluss .rpc .messages .PbLakeTieringTableInfo ;
4148import org .apache .fluss .rpc .metrics .ClientMetricGroup ;
4249import org .apache .fluss .utils .MapUtils ;
43-
44- import org .apache .flink .api .connector .source .SourceEvent ;
45- import org .apache .flink .api .connector .source .SplitEnumerator ;
46- import org .apache .flink .api .connector .source .SplitEnumeratorContext ;
47- import org .apache .flink .api .java .tuple .Tuple3 ;
48- import org .apache .flink .metrics .groups .SplitEnumeratorMetricGroup ;
49- import org .apache .flink .util .FlinkRuntimeException ;
5050import org .slf4j .Logger ;
5151import org .slf4j .LoggerFactory ;
5252
5353import javax .annotation .Nullable ;
54-
5554import java .io .IOException ;
55+ import java .time .Duration ;
5656import java .util .ArrayList ;
57+ import java .util .Collections ;
5758import java .util .HashMap ;
59+ import java .util .HashSet ;
5860import java .util .List ;
5961import java .util .Map ;
6062import java .util .Set ;
8587public class TieringSourceEnumerator
8688 implements SplitEnumerator <TieringSplit , TieringSourceEnumeratorState > {
8789
90+ private static final long TIERING_TIMEOUT_MS = Duration .ofMinutes (10 ).toMillis ();
91+
8892 private static final Logger LOG = LoggerFactory .getLogger (TieringSourceEnumerator .class );
8993
9094 private final Configuration flussConf ;
@@ -93,6 +97,8 @@ public class TieringSourceEnumerator
9397 private final long pollTieringTableIntervalMs ;
9498 private final List <TieringSplit > pendingSplits ;
9599 private final Set <Integer > readersAwaitingSplit ;
100+
101+ private final Map <Long , Long > tieringTableDeadline ;
96102 private final Map <Long , Long > tieringTableEpochs ;
97103 private final Map <Long , Long > failedTableEpochs ;
98104 private final Map <Long , Long > finishedTableEpochs ;
@@ -120,6 +126,7 @@ public TieringSourceEnumerator(
120126 this .tieringTableEpochs = MapUtils .newConcurrentHashMap ();
121127 this .finishedTableEpochs = MapUtils .newConcurrentHashMap ();
122128 this .failedTableEpochs = MapUtils .newConcurrentHashMap ();
129+ this .tieringTableDeadline = MapUtils .newConcurrentHashMap ();
123130 }
124131
125132 @ Override
@@ -167,6 +174,9 @@ public void handleSplitRequest(int subtaskId, @Nullable String requesterHostname
167174 readersAwaitingSplit .add (subtaskId );
168175 this .context .callAsync (
169176 this ::requestTieringTableSplitsViaHeartBeat , this ::generateAndAssignSplits );
177+
178+ this .context .callAsync (
179+ this ::checkTieringTimeoutTables , this ::handleTieringTimeoutTables , 10_000L , 10_000 );
170180 }
171181
172182 @ Override
@@ -236,6 +246,26 @@ public void handleSourceEvent(int subtaskId, SourceEvent sourceEvent) {
236246 }
237247 }
238248
249+ private Set <Long > checkTieringTimeoutTables () {
250+ Set <Long > tieringTimeoutTables = new HashSet <>();
251+
252+ }
253+
254+ private void handleTieringTimeoutTables (Set <Long > tieringTimeOutTables , Throwable throwable ) {
255+ if (throwable != null ) {
256+ LOG .error ("Fail to check tiering timeout tables." , throwable );
257+ return ;
258+ }
259+
260+ for (Long tieringTimeOutTable : tieringTimeOutTables ) {
261+ Set <Integer > readers = new HashSet <>(context .registeredReaders ().keySet ());
262+ for (int reader : readers ) {
263+ context .sendEventToSourceReader (
264+ reader , new TieringTimeoutEvent (tieringTimeOutTable ));
265+ }
266+ }
267+ }
268+
239269 private void generateAndAssignSplits (
240270 @ Nullable Tuple3 <Long , Long , TablePath > tieringTable , Throwable throwable ) {
241271 if (throwable != null ) {
@@ -260,6 +290,12 @@ private void assignSplits() {
260290 if (!pendingSplits .isEmpty ()) {
261291 TieringSplit tieringSplit = pendingSplits .remove (0 );
262292 context .assignSplit (tieringSplit , nextAwaitingReader );
293+
294+ long tableId = tieringSplit .getTableBucket ().getTableId ();
295+ if (!tieringTableDeadline .containsKey (tableId )) {
296+ tieringTableDeadline .put (
297+ tableId , System .currentTimeMillis () + TIERING_TIMEOUT_MS );
298+ }
263299 readersAwaitingSplit .remove (nextAwaitingReader );
264300 }
265301 }
@@ -324,6 +360,8 @@ private void generateTieringSplits(Tuple3<Long, Long, TablePath> tieringTable)
324360 List <TieringSplit > tieringSplits =
325361 populateNumberOfTieringSplits (
326362 splitGenerator .generateTableSplits (tieringTable .f2 ));
363+ // shuffle tiering split to avoid splits tiering skew
364+ Collections .shuffle (tieringSplits );
327365 LOG .info (
328366 "Generate Tiering {} splits for table {} with cost {}ms." ,
329367 tieringSplits .size (),
0 commit comments