This is an automated email from the ASF dual-hosted git repository.

vinoth pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hudi.git


The following commit(s) were added to refs/heads/master by this push:
     new 450a3c27ce4 [HUDI-9438] Fix conflict handling for compaction instants 
for v8 tables (#13347)
450a3c27ce4 is described below

commit 450a3c27ce4a31524ac6d6a971a39c4ad35490ac
Author: Tim Brown <[email protected]>
AuthorDate: Fri May 30 09:45:46 2025 -0500

    [HUDI-9438] Fix conflict handling for compaction instants for v8 tables 
(#13347)
    
    * fix conflict handling for compaction given completion time changes
    
    * consolidate tests
    
    * split handling into two methods for ease of reading and debugging
    
    * extract common parts of the code
---
 ...urrentFileWritesConflictResolutionStrategy.java |  71 +++++++++++--
 ...urrentFileWritesConflictResolutionStrategy.java | 111 ++++++++++++++++-----
 ...itesConflictResolutionStrategyWithMORTable.java |  90 -----------------
 .../hudi/client/TestHoodieClientMultiWriter.java   |  21 +---
 4 files changed, 155 insertions(+), 138 deletions(-)

diff --git 
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/SimpleConcurrentFileWritesConflictResolutionStrategy.java
 
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/SimpleConcurrentFileWritesConflictResolutionStrategy.java
index 8cbc141e0e8..a3686288ba0 100644
--- 
a/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/SimpleConcurrentFileWritesConflictResolutionStrategy.java
+++ 
b/hudi-client/hudi-client-common/src/main/java/org/apache/hudi/client/transaction/SimpleConcurrentFileWritesConflictResolutionStrategy.java
@@ -19,8 +19,10 @@
 package org.apache.hudi.client.transaction;
 
 import org.apache.hudi.common.model.HoodieCommitMetadata;
+import org.apache.hudi.common.model.HoodieTableType;
 import org.apache.hudi.common.model.WriteOperationType;
 import org.apache.hudi.common.table.HoodieTableMetaClient;
+import org.apache.hudi.common.table.HoodieTableVersion;
 import org.apache.hudi.common.table.timeline.HoodieActiveTimeline;
 import org.apache.hudi.common.table.timeline.HoodieInstant;
 import org.apache.hudi.common.table.timeline.HoodieTimeline;
@@ -36,6 +38,7 @@ import org.slf4j.LoggerFactory;
 import java.util.ConcurrentModificationException;
 import java.util.HashSet;
 import java.util.Set;
+import java.util.function.Predicate;
 import java.util.stream.Stream;
 
 import static 
org.apache.hudi.common.table.timeline.InstantComparison.GREATER_THAN;
@@ -53,26 +56,80 @@ public class 
SimpleConcurrentFileWritesConflictResolutionStrategy
   @Override
   public Stream<HoodieInstant> getCandidateInstants(HoodieTableMetaClient 
metaClient, HoodieInstant currentInstant,
                                                     Option<HoodieInstant> 
lastSuccessfulInstant) {
+    if 
(metaClient.getTableConfig().getTableVersion().greaterThanOrEquals(HoodieTableVersion.EIGHT))
 {
+      return getCandidateInstantsV8AndAbove(metaClient, currentInstant, 
lastSuccessfulInstant);
+    } else {
+      return getCandidateInstantsPreV8(metaClient, currentInstant, 
lastSuccessfulInstant);
+    }
+  }
+
+  /**
+   * To find which instants are conflicting for table versions 8 and above, we 
apply the following logic:
+   * <ul>
+   *   <li>Get completed instants timeline only for commits that have happened 
since the last successful write.</li>
+   *   <li>Get any completed replace commit that happened since the last 
successful write and any pending replace commit.</li>
+   * </ul>
+   * @param metaClient table meta client
+   * @param currentInstant the instant for the write this client is attempting 
to commit
+   * @param lastSuccessfulInstant the last successful write before this commit 
started
+   * @return a stream of instants that are candidates for conflict resolution
+   */
+  private Stream<HoodieInstant> 
getCandidateInstantsV8AndAbove(HoodieTableMetaClient metaClient, HoodieInstant 
currentInstant,
+                                                               
Option<HoodieInstant> lastSuccessfulInstant) {
     HoodieActiveTimeline activeTimeline = metaClient.getActiveTimeline();
-    // To find which instants are conflicting, we apply the following logic
-    // 1. Get completed instants timeline only for commits that have happened 
since the last successful write.
-    // 2. Get any scheduled or completed compaction that have started and/or 
finished after the current instant.
-    // 3. Get any completed replace commit that happened since the last 
successful write and any pending replace commit.
-    // We need to check for write conflicts since they may have mutated the 
same files that are being newly created by the current write.
+    boolean isMoRTable = metaClient.getTableType() == 
HoodieTableType.MERGE_ON_READ;
     Stream<HoodieInstant> completedCommitsInstantStream = activeTimeline
         .getCommitsTimeline()
         .filterCompletedInstants()
+        .filter(instant -> !isMoRTable || 
!instant.getAction().equals(HoodieTimeline.COMMIT_ACTION))
         .findInstantsAfter(lastSuccessfulInstant.isPresent() ? 
lastSuccessfulInstant.get().requestedTime() : HoodieTimeline.INIT_INSTANT_TS)
         .getInstantsAsStream();
 
+    Stream<HoodieInstant> clusteringAndReplaceCommitInstants = activeTimeline
+        .filterPendingReplaceOrClusteringTimeline()
+        .filter(instant -> 
isClusteringOrRecentlyRequestedInstant(activeTimeline, metaClient, 
currentInstant).test(instant))
+        .getInstantsAsStream();
+
+    return Stream.concat(completedCommitsInstantStream, 
clusteringAndReplaceCommitInstants);
+  }
+
+  /**
+   * To find which instants are conflicting for table versions below 8, we 
apply the following logic:
+   * <ul>
+   *   <li>Get completed instants timeline only for commits that have happened 
since the last successful write.</li>
+   *   <li>Get any scheduled or completed compaction that have started and/or 
finished after the current instant.</li>
+   *   <li>Get any completed replace commit that happened since the last 
successful write and any pending replace commit.</li>
+   * </ul>
+   * @param metaClient table meta client
+   * @param currentInstant the instant for the write this client is attempting 
to commit
+   * @param lastSuccessfulInstant the last successful write before this commit 
started
+   * @return a stream of instants that are candidates for conflict resolution
+   */
+  private Stream<HoodieInstant> 
getCandidateInstantsPreV8(HoodieTableMetaClient metaClient, HoodieInstant 
currentInstant,
+                                                          
Option<HoodieInstant> lastSuccessfulInstant) {
+    HoodieActiveTimeline activeTimeline = metaClient.getActiveTimeline();
+    Stream<HoodieInstant> completedCommitsInstantStream = 
getCommitsCompletedSinceLastCommit(lastSuccessfulInstant, activeTimeline);
+
     Stream<HoodieInstant> compactionAndClusteringPendingTimeline = 
activeTimeline
         .filterPendingReplaceClusteringAndCompactionTimeline()
-        .filter(instant -> ClusteringUtils.isClusteringInstant(activeTimeline, 
instant, metaClient.getInstantGenerator())
-            || (!HoodieTimeline.CLUSTERING_ACTION.equals(instant.getAction()) 
&& compareTimestamps(instant.requestedTime(), GREATER_THAN, 
currentInstant.requestedTime())))
+        .filter(instant -> 
isClusteringOrRecentlyRequestedInstant(activeTimeline, metaClient, 
currentInstant).test(instant))
         .getInstantsAsStream();
     return Stream.concat(completedCommitsInstantStream, 
compactionAndClusteringPendingTimeline);
   }
 
+  private static Stream<HoodieInstant> 
getCommitsCompletedSinceLastCommit(Option<HoodieInstant> lastSuccessfulInstant, 
HoodieActiveTimeline activeTimeline) {
+    return activeTimeline
+        .getCommitsTimeline()
+        .filterCompletedInstants()
+        
.findInstantsAfter(lastSuccessfulInstant.map(HoodieInstant::requestedTime).orElse(HoodieTimeline.INIT_INSTANT_TS))
+        .getInstantsAsStream();
+  }
+
+  private Predicate<HoodieInstant> 
isClusteringOrRecentlyRequestedInstant(HoodieActiveTimeline activeTimeline, 
HoodieTableMetaClient metaClient, HoodieInstant currentInstant) {
+    return instant -> ClusteringUtils.isClusteringInstant(activeTimeline, 
instant, metaClient.getInstantGenerator())
+        || (!HoodieTimeline.CLUSTERING_ACTION.equals(instant.getAction()) && 
compareTimestamps(instant.requestedTime(), GREATER_THAN, 
currentInstant.requestedTime()));
+  }
+
   @Override
   public boolean hasConflict(ConcurrentOperation thisOperation, 
ConcurrentOperation otherOperation) {
     // TODO : UUID's can clash even for insert/insert, handle that case.
diff --git 
a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/client/transaction/TestSimpleConcurrentFileWritesConflictResolutionStrategy.java
 
b/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/client/transaction/TestSimpleConcurrentFileWritesConflictResolutionStrategy.java
index a749fce98f4..443cd02ff02 100644
--- 
a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/client/transaction/TestSimpleConcurrentFileWritesConflictResolutionStrategy.java
+++ 
b/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/client/transaction/TestSimpleConcurrentFileWritesConflictResolutionStrategy.java
@@ -20,6 +20,7 @@ package org.apache.hudi.client.transaction;
 
 import org.apache.hudi.client.utils.TransactionUtils;
 import org.apache.hudi.common.model.HoodieCommitMetadata;
+import org.apache.hudi.common.model.HoodieTableType;
 import org.apache.hudi.common.model.WriteOperationType;
 import org.apache.hudi.common.table.timeline.HoodieActiveTimeline;
 import org.apache.hudi.common.table.timeline.HoodieInstant;
@@ -31,10 +32,10 @@ import org.apache.hudi.common.util.Option;
 import org.apache.hudi.exception.HoodieWriteConflictException;
 
 import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
 import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
 
-import java.io.IOException;
 import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
@@ -60,13 +61,9 @@ import static 
org.apache.hudi.common.testutils.HoodieTestUtils.INSTANT_GENERATOR
 
 public class TestSimpleConcurrentFileWritesConflictResolutionStrategy extends 
HoodieCommonTestHarness {
 
-  @BeforeEach
-  public void init() throws IOException {
-    initMetaClient();
-  }
-
   @Test
   public void testNoConcurrentWrites() throws Exception {
+    initMetaClient();
     String newInstantTime = HoodieTestTable.makeNewCommitTime();
     createCommit(newInstantTime, metaClient);
     // consider commits before this are all successful
@@ -82,6 +79,7 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
 
   @Test
   public void testConcurrentWrites() throws Exception {
+    initMetaClient();
     String newInstantTime = HoodieTestTable.makeNewCommitTime();
     createCommit(newInstantTime, metaClient);
     // consider commits before this are all successful
@@ -99,6 +97,7 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
 
   @Test
   public void testConcurrentWritesWithInterleavingSuccessfulCommit() throws 
Exception {
+    initMetaClient();
     createCommit(metaClient.createNewInstantTime(), metaClient);
     HoodieActiveTimeline timeline = metaClient.getActiveTimeline();
     // consider commits before this are all successful
@@ -126,6 +125,7 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
 
   @Test
   public void testConcurrentWritesWithReplaceInflightCommit() throws Exception 
{
+    initMetaClient();
     String currentWriterInstant = metaClient.createNewInstantTime();
     createInflightCommit(currentWriterInstant, metaClient);
     Option<HoodieInstant> currentInstant = 
Option.of(INSTANT_GENERATOR.createNewInstant(State.INFLIGHT, 
HoodieTimeline.COMMIT_ACTION, currentWriterInstant));
@@ -152,6 +152,7 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
 
   @Test
   public void testConcurrentWritesWithClusteringInflightCommit() throws 
Exception {
+    initMetaClient();
     // writer 1 starts
     String currentWriterInstant = metaClient.createNewInstantTime();
     createInflightCommit(currentWriterInstant, metaClient);
@@ -179,6 +180,7 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
 
   @Test
   public void testConcurrentWritesWithLegacyClusteringInflightCommit() throws 
Exception {
+    initMetaClient();
     String clusteringInstantTime = metaClient.createNewInstantTime();
     // create a replace commit with a clustering operation to mimic a commit 
written by a v6 writer
     HoodieTestTable.of(metaClient).addRequestedReplace(clusteringInstantTime, 
Option.of(buildRequestedReplaceMetadata("file-1", WriteOperationType.CLUSTER)));
@@ -205,8 +207,10 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
     Assertions.assertThrows(HoodieWriteConflictException.class, () -> 
strategy.resolveConflict(null, thisCommitOperation, thatCommitOperation));
   }
 
-  @Test
-  public void testConcurrentWritesWithInterleavingScheduledCompaction() throws 
Exception {
+  @ParameterizedTest
+  @ValueSource(booleans = {false, true})
+  public void testConcurrentWritesWithInterleavingScheduledCompaction(boolean 
preTableVersion8) throws Exception {
+    initMetaClient(preTableVersion8, HoodieTableType.MERGE_ON_READ);
     createCommit(metaClient.createNewInstantTime(), metaClient);
     HoodieActiveTimeline timeline = metaClient.getActiveTimeline();
     // consider commits before this are all successful
@@ -224,16 +228,23 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
     metaClient.reloadActiveTimeline();
     List<HoodieInstant> candidateInstants = 
strategy.getCandidateInstants(metaClient, currentInstant.get(), 
lastSuccessfulInstant).collect(
         Collectors.toList());
-    // writer 1 conflicts with scheduled compaction plan 1
-    Assertions.assertEquals(1, candidateInstants.size());
-    ConcurrentOperation thatCommitOperation = new 
ConcurrentOperation(candidateInstants.get(0), metaClient);
-    ConcurrentOperation thisCommitOperation = new 
ConcurrentOperation(currentInstant.get(), currentMetadata);
-    Assertions.assertTrue(strategy.hasConflict(thisCommitOperation, 
thatCommitOperation));
-    Assertions.assertThrows(HoodieWriteConflictException.class, () -> 
strategy.resolveConflict(null, thisCommitOperation, thatCommitOperation));
+    if (preTableVersion8) {
+      // writer 1 conflicts with scheduled compaction plan 1
+      Assertions.assertEquals(1, candidateInstants.size());
+      ConcurrentOperation thatCommitOperation = new 
ConcurrentOperation(candidateInstants.get(0), metaClient);
+      ConcurrentOperation thisCommitOperation = new 
ConcurrentOperation(currentInstant.get(), currentMetadata);
+      Assertions.assertTrue(strategy.hasConflict(thisCommitOperation, 
thatCommitOperation));
+      Assertions.assertThrows(HoodieWriteConflictException.class, () -> 
strategy.resolveConflict(null, thisCommitOperation, thatCommitOperation));
+    } else {
+      // writer will not have conflicts with compaction since ordering is now 
based on completion time to avoid these conflicts
+      Assertions.assertTrue(candidateInstants.isEmpty());
+    }
   }
 
-  @Test
-  public void testConcurrentWritesWithInterleavingSuccessfulCompaction() 
throws Exception {
+  @ParameterizedTest
+  @ValueSource(booleans = {false, true})
+  public void testConcurrentWritesWithInterleavingSuccessfulCompaction(boolean 
preTableVersion8) throws Exception {
+    initMetaClient(preTableVersion8, HoodieTableType.MERGE_ON_READ);
     createCommit(metaClient.createNewInstantTime(), metaClient);
     HoodieActiveTimeline timeline = metaClient.getActiveTimeline();
     // consider commits before this are all successful
@@ -251,12 +262,60 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
     metaClient.reloadActiveTimeline();
     List<HoodieInstant> candidateInstants = 
strategy.getCandidateInstants(metaClient, currentInstant.get(), 
lastSuccessfulInstant).collect(
         Collectors.toList());
-    // writer 1 conflicts with compaction 1
-    Assertions.assertEquals(1, candidateInstants.size());
-    ConcurrentOperation thatCommitOperation = new 
ConcurrentOperation(candidateInstants.get(0), metaClient);
-    ConcurrentOperation thisCommitOperation = new 
ConcurrentOperation(currentInstant.get(), currentMetadata);
-    Assertions.assertTrue(strategy.hasConflict(thisCommitOperation, 
thatCommitOperation));
-    Assertions.assertThrows(HoodieWriteConflictException.class, () -> 
strategy.resolveConflict(null, thisCommitOperation, thatCommitOperation));
+    if (preTableVersion8) {
+      // writer 1 conflicts with compaction 1
+      Assertions.assertEquals(1, candidateInstants.size());
+      ConcurrentOperation thatCommitOperation = new 
ConcurrentOperation(candidateInstants.get(0), metaClient);
+      ConcurrentOperation thisCommitOperation = new 
ConcurrentOperation(currentInstant.get(), currentMetadata);
+      Assertions.assertTrue(strategy.hasConflict(thisCommitOperation, 
thatCommitOperation));
+      Assertions.assertThrows(HoodieWriteConflictException.class, () -> 
strategy.resolveConflict(null, thisCommitOperation, thatCommitOperation));
+    } else {
+      // writer will not have conflicts with compaction since ordering is now 
based on completion time to avoid these conflicts
+      Assertions.assertTrue(candidateInstants.isEmpty());
+    }
+  }
+
+  @ParameterizedTest
+  @ValueSource(booleans = {false, true})
+  public void testConcurrentWritesWithInterleavingInflightCompaction(boolean 
preTableVersion8) throws Exception {
+    initMetaClient(preTableVersion8, HoodieTableType.MERGE_ON_READ);
+    createCommit(metaClient.createNewInstantTime(), metaClient);
+    HoodieActiveTimeline timeline = metaClient.getActiveTimeline();
+    // Consider commits before this are all successful.
+    Option<HoodieInstant> lastSuccessfulInstant = 
timeline.getCommitsTimeline().filterCompletedInstants().lastInstant();
+
+    // Writer 1 starts.
+    String currentWriterInstant = metaClient.createNewInstantTime();
+    createInflightCommit(currentWriterInstant, metaClient);
+
+    // Compaction 1 gets scheduled and becomes inflight.
+    String newInstantTime = metaClient.createNewInstantTime();
+    createPendingCompaction(newInstantTime, metaClient);
+
+    // Writer 1 tries to commit.
+    Option<HoodieInstant> currentInstant = Option.of(
+        INSTANT_GENERATOR.createNewInstant(HoodieInstant.State.INFLIGHT, 
HoodieTimeline.DELTA_COMMIT_ACTION, currentWriterInstant));
+    HoodieCommitMetadata currentMetadata = 
createCommitMetadata(currentWriterInstant);
+    metaClient.reloadActiveTimeline();
+
+    // Do conflict resolution.
+    SimpleConcurrentFileWritesConflictResolutionStrategy strategy =
+        new SimpleConcurrentFileWritesConflictResolutionStrategy();
+    List<HoodieInstant> candidateInstants = strategy.getCandidateInstants(
+        metaClient, currentInstant.get(), 
lastSuccessfulInstant).collect(Collectors.toList());
+
+    if (preTableVersion8) {
+      Assertions.assertEquals(1, candidateInstants.size());
+      ConcurrentOperation thatCommitOperation = new 
ConcurrentOperation(candidateInstants.get(0), metaClient);
+      ConcurrentOperation thisCommitOperation = new 
ConcurrentOperation(currentInstant.get(), currentMetadata);
+      Assertions.assertTrue(strategy.hasConflict(thisCommitOperation, 
thatCommitOperation));
+      Assertions.assertThrows(
+          HoodieWriteConflictException.class,
+          () -> strategy.resolveConflict(null, thisCommitOperation, 
thatCommitOperation));
+    } else {
+      // Writer will not have conflicts with compaction since ordering is now 
based on completion time to avoid these conflicts.
+      Assertions.assertTrue(candidateInstants.isEmpty());
+    }
   }
 
   /**
@@ -264,6 +323,7 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
    */
   @Test
   public void testConcurrentWriteAndCompactionScheduledEarlier() throws 
Exception {
+    initMetaClient(false, HoodieTableType.MERGE_ON_READ);
     createCommit(metaClient.createNewInstantTime(), metaClient);
     // compaction 1 gets scheduled
     String newInstantTime = metaClient.createNewInstantTime();
@@ -286,6 +346,7 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
 
   @Test
   public void testConcurrentWritesWithInterleavingScheduledCluster() throws 
Exception {
+    initMetaClient(false, HoodieTableType.MERGE_ON_READ);
     createCommit(metaClient.createNewInstantTime(), metaClient);
     HoodieActiveTimeline timeline = metaClient.getActiveTimeline();
     // consider commits before this are all successful
@@ -313,6 +374,7 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
 
   @Test
   public void testConcurrentWritesWithInterleavingSuccessfulCluster() throws 
Exception {
+    initMetaClient();
     createCommit(metaClient.createNewInstantTime(), metaClient);
     HoodieActiveTimeline timeline = metaClient.getActiveTimeline();
     // consider commits before this are all successful
@@ -340,6 +402,7 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
 
   @Test
   public void testConcurrentWritesWithInterleavingSuccessfulReplace() throws 
Exception {
+    initMetaClient();
     createCommit(metaClient.createNewInstantTime(), metaClient);
     HoodieActiveTimeline timeline = metaClient.getActiveTimeline();
     // consider commits before this are all successful
@@ -367,6 +430,7 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
 
   @Test
   public void testConcurrentWritesWithPendingInsertOverwriteReplace() throws 
Exception {
+    initMetaClient();
     createCommit(metaClient.createNewInstantTime(), metaClient);
     HoodieActiveTimeline timeline = metaClient.getActiveTimeline();
     // consider commits before this are all successful
@@ -396,6 +460,7 @@ public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategy extends Ho
   // try to simulate HUDI-3355
   @Test
   public void testConcurrentWritesWithPendingInstants() throws Exception {
+    initMetaClient(false, HoodieTableType.MERGE_ON_READ);
     // step1: create a pending replace/commit/compact instant: C1,C11,C12
     String newInstantTimeC1 = metaClient.createNewInstantTime();
     createPendingCluster(newInstantTimeC1, WriteOperationType.CLUSTER, 
metaClient);
diff --git 
a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/client/transaction/TestSimpleConcurrentFileWritesConflictResolutionStrategyWithMORTable.java
 
b/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/client/transaction/TestSimpleConcurrentFileWritesConflictResolutionStrategyWithMORTable.java
deleted file mode 100644
index c94d3009cd9..00000000000
--- 
a/hudi-client/hudi-client-common/src/test/java/org/apache/hudi/client/transaction/TestSimpleConcurrentFileWritesConflictResolutionStrategyWithMORTable.java
+++ /dev/null
@@ -1,90 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *   http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.hudi.client.transaction;
-
-import org.apache.hudi.common.model.HoodieCommitMetadata;
-import org.apache.hudi.common.model.HoodieTableType;
-import org.apache.hudi.common.table.timeline.HoodieActiveTimeline;
-import org.apache.hudi.common.table.timeline.HoodieInstant;
-import org.apache.hudi.common.table.timeline.HoodieTimeline;
-import org.apache.hudi.common.testutils.HoodieCommonTestHarness;
-import org.apache.hudi.common.util.Option;
-import org.apache.hudi.exception.HoodieWriteConflictException;
-
-import org.junit.jupiter.api.Assertions;
-import org.junit.jupiter.api.BeforeEach;
-import org.junit.jupiter.api.Test;
-
-import java.io.IOException;
-import java.util.List;
-import java.util.stream.Collectors;
-
-import static 
org.apache.hudi.client.transaction.TestConflictResolutionStrategyUtil.createCommit;
-import static 
org.apache.hudi.client.transaction.TestConflictResolutionStrategyUtil.createCommitMetadata;
-import static 
org.apache.hudi.client.transaction.TestConflictResolutionStrategyUtil.createInflightCommit;
-import static 
org.apache.hudi.client.transaction.TestConflictResolutionStrategyUtil.createPendingCompaction;
-import static 
org.apache.hudi.common.testutils.HoodieTestUtils.INSTANT_GENERATOR;
-
-public class 
TestSimpleConcurrentFileWritesConflictResolutionStrategyWithMORTable extends 
HoodieCommonTestHarness {
-  @Override
-  protected HoodieTableType getTableType() {
-    return HoodieTableType.MERGE_ON_READ;
-  }
-
-  @BeforeEach
-  public void init() throws IOException {
-    initMetaClient();
-  }
-
-  @Test
-  public void testConcurrentWritesWithInterleavingInflightCompaction() throws 
Exception {
-    createCommit(metaClient.createNewInstantTime(), metaClient);
-    HoodieActiveTimeline timeline = metaClient.getActiveTimeline();
-    // Consider commits before this are all successful.
-    Option<HoodieInstant> lastSuccessfulInstant = 
timeline.getCommitsTimeline().filterCompletedInstants().lastInstant();
-
-    // Writer 1 starts.
-    String currentWriterInstant = metaClient.createNewInstantTime();
-    createInflightCommit(currentWriterInstant, metaClient);
-
-    // Compaction 1 gets scheduled and becomes inflight.
-    String newInstantTime = metaClient.createNewInstantTime();
-    createPendingCompaction(newInstantTime, metaClient);
-
-    // Writer 1 tries to commit.
-    Option<HoodieInstant> currentInstant = Option.of(
-        INSTANT_GENERATOR.createNewInstant(HoodieInstant.State.INFLIGHT, 
HoodieTimeline.DELTA_COMMIT_ACTION, currentWriterInstant));
-    HoodieCommitMetadata currentMetadata = 
createCommitMetadata(currentWriterInstant);
-    metaClient.reloadActiveTimeline();
-
-    // Do conflict resolution.
-    SimpleConcurrentFileWritesConflictResolutionStrategy strategy =
-        new SimpleConcurrentFileWritesConflictResolutionStrategy();
-    List<HoodieInstant> candidateInstants = strategy.getCandidateInstants(
-        metaClient, currentInstant.get(), 
lastSuccessfulInstant).collect(Collectors.toList());
-    Assertions.assertEquals(1, candidateInstants.size());
-    ConcurrentOperation thatCommitOperation = new 
ConcurrentOperation(candidateInstants.get(0), metaClient);
-    ConcurrentOperation thisCommitOperation = new 
ConcurrentOperation(currentInstant.get(), currentMetadata);
-    Assertions.assertTrue(strategy.hasConflict(thisCommitOperation, 
thatCommitOperation));
-    Assertions.assertThrows(
-        HoodieWriteConflictException.class,
-        () -> strategy.resolveConflict(null, thisCommitOperation, 
thatCommitOperation));
-  }
-}
diff --git 
a/hudi-spark-datasource/hudi-spark/src/test/java/org/apache/hudi/client/TestHoodieClientMultiWriter.java
 
b/hudi-spark-datasource/hudi-spark/src/test/java/org/apache/hudi/client/TestHoodieClientMultiWriter.java
index 70f05439b9f..328457ac8be 100644
--- 
a/hudi-spark-datasource/hudi-spark/src/test/java/org/apache/hudi/client/TestHoodieClientMultiWriter.java
+++ 
b/hudi-spark-datasource/hudi-spark/src/test/java/org/apache/hudi/client/TestHoodieClientMultiWriter.java
@@ -827,24 +827,9 @@ public class TestHoodieClientMultiWriter extends 
HoodieClientTestBase {
       // We want the upsert to go through only after the compaction
       // and cleaning schedule completion. So, waiting on latch here.
       latchCountDownAndWait(scheduleCountDownLatch, waitAndRunSecond);
-      if (tableType == HoodieTableType.MERGE_ON_READ && !(resolutionStrategy 
instanceof PreferWriterConflictResolutionStrategy)) {
-        // HUDI-6897: Improve 
SimpleConcurrentFileWritesConflictResolutionStrategy for NB-CC
-        // There is no need to throw concurrent modification exception for the 
simple strategy under NB-CC, because the compactor would finally resolve the 
conflicts instead.
-
-        // Since the concurrent modifications went in, this upsert has
-        // to fail
-        assertThrows(HoodieWriteConflictException.class, () -> {
-          createCommitWithUpserts(cfg, client1, thirdCommitTime, 
Option.of(commitTimeBetweenPrevAndNew), upsertCommitTime, numRecords);
-        });
-      } else {
-        // We don't have the compaction for COW and so this upsert
-        // has to pass
-        final String newCommitTime = client1.createNewInstantTime();
-        assertDoesNotThrow(() -> {
-          createCommitWithUpserts(cfg, client1, thirdCommitTime, 
Option.of(commitTimeBetweenPrevAndNew), newCommitTime, numRecords);
-        });
-        validInstants.add(newCommitTime);
-      }
+      // Writes should pass since scheduled compaction does not conflict with 
upsert for v8 and above
+      assertDoesNotThrow(() -> createCommitWithUpserts(cfg, client1, 
thirdCommitTime, Option.of(commitTimeBetweenPrevAndNew), upsertCommitTime, 
numRecords));
+      validInstants.add(upsertCommitTime);
     });
 
     Future future2 = executors.submit(() -> {

Reply via email to