|
21 | 21 | import org.apache.hudi.common.engine.HoodieEngineContext; |
22 | 22 | import org.apache.hudi.common.metrics.Registry; |
23 | 23 | import org.apache.hudi.common.table.marker.MarkerOperation; |
| 24 | +import org.apache.hudi.common.table.timeline.HoodieInstant; |
24 | 25 | import org.apache.hudi.common.table.timeline.HoodieTimeline; |
25 | 26 | import org.apache.hudi.common.table.timeline.dto.BaseFileDTO; |
26 | 27 | import org.apache.hudi.common.table.timeline.dto.ClusteringOpDTO; |
|
33 | 34 | import org.apache.hudi.common.table.view.RemoteHoodieTableFileSystemView; |
34 | 35 | import org.apache.hudi.common.table.view.SyncableFileSystemView; |
35 | 36 | import org.apache.hudi.common.util.HoodieTimer; |
| 37 | +import org.apache.hudi.common.util.Option; |
36 | 38 | import org.apache.hudi.exception.HoodieException; |
37 | 39 | import org.apache.hudi.timeline.service.handlers.BaseFileHandler; |
38 | 40 | import org.apache.hudi.timeline.service.handlers.FileSliceHandler; |
@@ -502,14 +504,15 @@ public void handle(@NotNull Context context) throws Exception { |
502 | 504 | if (refreshCheck) { |
503 | 505 | long beginFinalCheck = System.currentTimeMillis(); |
504 | 506 | if (isLocalViewBehind(context)) { |
505 | | - String lastInstantTs = context.queryParam(RemoteHoodieTableFileSystemView.LAST_INSTANT_TS, |
| 507 | + String lastKnownInstantFromClient = context.queryParam(RemoteHoodieTableFileSystemView.LAST_INSTANT_TS, |
506 | 508 | HoodieTimeline.INVALID_INSTANT_TS); |
| 509 | + String timelineHashFromClient = context.queryParam(RemoteHoodieTableFileSystemView.TIMELINE_HASH, ""); |
507 | 510 | HoodieTimeline localTimeline = |
508 | 511 | viewManager.getFileSystemView(context.queryParam(RemoteHoodieTableFileSystemView.BASEPATH_PARAM)).getTimeline(); |
509 | | - if (shouldThrowExceptionIfLocalViewBehind(localTimeline, lastInstantTs)) { |
| 512 | + if (shouldThrowExceptionIfLocalViewBehind(localTimeline, timelineHashFromClient)) { |
510 | 513 | String errMsg = |
511 | 514 | "Last known instant from client was " |
512 | | - + lastInstantTs |
| 515 | + + lastKnownInstantFromClient |
513 | 516 | + " but server has the following timeline " |
514 | 517 | + localTimeline.getInstants().collect(Collectors.toList()); |
515 | 518 | throw new BadRequestResponse(errMsg); |
@@ -547,12 +550,12 @@ public void handle(@NotNull Context context) throws Exception { |
547 | 550 | /** |
548 | 551 | * Determine whether to throw an exception when local view of table's timeline is behind that of client's view. |
549 | 552 | */ |
550 | | - private boolean shouldThrowExceptionIfLocalViewBehind(HoodieTimeline localTimeline, String lastInstantTs) { |
551 | | - HoodieTimeline afterLastInstantTimeLine = localTimeline.findInstantsAfter(lastInstantTs).filterCompletedInstants(); |
| 553 | + private boolean shouldThrowExceptionIfLocalViewBehind(HoodieTimeline localTimeline, String timelineHashFromClient) { |
| 554 | + Option<HoodieInstant> lastInstant = localTimeline.lastInstant(); |
552 | 555 | // When performing async clean, we may have one more .clean.completed after lastInstantTs. |
553 | 556 | // In this case, we do not need to throw an exception. |
554 | | - if (afterLastInstantTimeLine.countInstants() == 1 |
555 | | - && afterLastInstantTimeLine.filter(s -> s.getAction().equals(HoodieTimeline.CLEAN_ACTION)).countInstants() == 1) { |
| 557 | + if (lastInstant.isPresent() && lastInstant.get().getAction().equals(HoodieTimeline.CLEAN_ACTION) |
| 558 | + && localTimeline.findInstantsBefore(lastInstant.get().getTimestamp()).getTimelineHash().equals(timelineHashFromClient)) { |
556 | 559 | return false; |
557 | 560 | } else { |
558 | 561 | return true; |
|
0 commit comments