wombatu-kun commented on code in PR #19369:
URL: https://github.com/apache/hudi/pull/19369#discussion_r3643043796


##########
hudi-client/hudi-client-common/src/main/java/org/apache/hudi/table/marker/TimelineServerBasedWriteMarkers.java:
##########
@@ -137,7 +139,7 @@ protected Option<StoragePath> create(String partitionPath, 
String fileName, IOTy
     if (success) {
       return Option.of(new 
StoragePath(FSUtils.constructAbsolutePath(markerDirPath, partitionPath), 
markerFileName));
     } else {
-      return Option.empty();
+      throw new HoodieIOException("[timeline-server-based] Failed to create 
marker for partition " + partitionPath + ", fileName " + fileName + " with 
IOType " + type);

Review Comment:
   A false result here does not mean the create failed: the server returns 
false when the marker already exists (MarkerDirState sets isSuccessful to 
!exists), and a genuine I/O failure already surfaces as HoodieRemoteException, 
not as false. So this throw fires on an already-existing marker, which 
createIfNotExists/createLogMarkerIfNotExists treat as a harmless Option.empty 
no-op - is turning already-exists into a hard failure intended, or should the 
throw be limited to a real create failure?



##########
hudi-client/hudi-spark-client/src/test/java/org/apache/hudi/table/marker/TestTimelineServerBasedWriteMarkers.java:
##########
@@ -162,6 +168,54 @@ private void restartServerAndClient(int 
numberOfSimulatedConnectionFailures,
     }
   }
 
+  @Test
+  public void testMarkerCreationFailure() throws IOException {
+    FileSystemViewStorageConfig.Builder builder = 
FileSystemViewStorageConfig.newBuilder().withRemoteServerHost("localhost")
+        .withRemoteServerPort(timelineService.getServerPort())
+        .withRemoteTimelineClientTimeoutSecs(DEFAULT_READ_TIMEOUT_SECS);
+    MockTimelineServerBasedWriteMarkers timelineServerBasedWriteMarkers = new 
MockTimelineServerBasedWriteMarkers(basePath, markerFolderPath.toString(), 
"000", builder.build());
+    // this should succeed.
+    timelineServerBasedWriteMarkers.create("2020/06/01", "file1", 
IOType.MERGE);
+
+    assertTrue(storage.exists(markerFolderPath));
+    assertTrue(writeMarkers.doesMarkerDirExist());
+
+    // lets fail the marker creation
+    timelineServerBasedWriteMarkers.failMarkerCreation = true;
+    try {
+      timelineServerBasedWriteMarkers.create("2020/06/01", "file2", 
IOType.MERGE);
+      fail("Should not have reached here");
+    } catch (HoodieIOException ioe) {
+      assertTrue(ioe.getMessage().contains("[timeline-server-based] Failed to 
create marker for partition"));
+    } finally {
+      if (timelineService != null) {
+        timelineService.close();
+      }
+    }
+  }
+
+  static class MockTimelineServerBasedWriteMarkers extends 
TimelineServerBasedWriteMarkers {
+
+    boolean failMarkerCreation = false;
+
+    public MockTimelineServerBasedWriteMarkers(HoodieTable table, String 
instantTime) {
+      super(table, instantTime);
+    }
+
+    MockTimelineServerBasedWriteMarkers(String basePath, String 
markerFolderPath, String instantTime, FileSystemViewStorageConfig 
fileSystemViewStorageConfig) {
+      super(basePath, markerFolderPath, instantTime, 
fileSystemViewStorageConfig);
+    }
+
+    @Override
+    boolean executeCreateMarkerRequest(Map<String, String> paramsMap, String 
partitionPath, String markerFileName) {
+      if (!failMarkerCreation) {
+        return super.executeCreateMarkerRequest(paramsMap, partitionPath, 
markerFileName);
+      } else {
+        return false;

Review Comment:
   Returning false here mirrors a create failure, but the real server also 
returns false when the marker already exists (MarkerDirState: !exists), so the 
test cannot tell a genuine failure from a benign already-exists and never 
covers createIfNotExists on an existing marker. Add a case that creates the 
same marker twice to lock down the intended behavior.



##########
hudi-client/hudi-spark-client/src/test/java/org/apache/hudi/table/marker/TestTimelineServerBasedWriteMarkers.java:
##########
@@ -162,6 +168,54 @@ private void restartServerAndClient(int 
numberOfSimulatedConnectionFailures,
     }
   }
 
+  @Test
+  public void testMarkerCreationFailure() throws IOException {
+    FileSystemViewStorageConfig.Builder builder = 
FileSystemViewStorageConfig.newBuilder().withRemoteServerHost("localhost")
+        .withRemoteServerPort(timelineService.getServerPort())
+        .withRemoteTimelineClientTimeoutSecs(DEFAULT_READ_TIMEOUT_SECS);
+    MockTimelineServerBasedWriteMarkers timelineServerBasedWriteMarkers = new 
MockTimelineServerBasedWriteMarkers(basePath, markerFolderPath.toString(), 
"000", builder.build());
+    // this should succeed.
+    timelineServerBasedWriteMarkers.create("2020/06/01", "file1", 
IOType.MERGE);
+
+    assertTrue(storage.exists(markerFolderPath));
+    assertTrue(writeMarkers.doesMarkerDirExist());
+
+    // lets fail the marker creation
+    timelineServerBasedWriteMarkers.failMarkerCreation = true;
+    try {
+      timelineServerBasedWriteMarkers.create("2020/06/01", "file2", 
IOType.MERGE);
+      fail("Should not have reached here");
+    } catch (HoodieIOException ioe) {
+      assertTrue(ioe.getMessage().contains("[timeline-server-based] Failed to 
create marker for partition"));
+    } finally {

Review Comment:
   @AfterEach cleanup() already closes timelineService, so closing it again in 
this finally double-closes the service. Drop the finally - the try only needs 
to wrap the failing create.



##########
hudi-client/hudi-spark-client/src/test/java/org/apache/hudi/table/marker/TestTimelineServerBasedWriteMarkers.java:
##########
@@ -162,6 +168,54 @@ private void restartServerAndClient(int 
numberOfSimulatedConnectionFailures,
     }
   }
 
+  @Test
+  public void testMarkerCreationFailure() throws IOException {
+    FileSystemViewStorageConfig.Builder builder = 
FileSystemViewStorageConfig.newBuilder().withRemoteServerHost("localhost")
+        .withRemoteServerPort(timelineService.getServerPort())
+        .withRemoteTimelineClientTimeoutSecs(DEFAULT_READ_TIMEOUT_SECS);
+    MockTimelineServerBasedWriteMarkers timelineServerBasedWriteMarkers = new 
MockTimelineServerBasedWriteMarkers(basePath, markerFolderPath.toString(), 
"000", builder.build());
+    // this should succeed.
+    timelineServerBasedWriteMarkers.create("2020/06/01", "file1", 
IOType.MERGE);
+
+    assertTrue(storage.exists(markerFolderPath));
+    assertTrue(writeMarkers.doesMarkerDirExist());
+
+    // lets fail the marker creation
+    timelineServerBasedWriteMarkers.failMarkerCreation = true;
+    try {
+      timelineServerBasedWriteMarkers.create("2020/06/01", "file2", 
IOType.MERGE);
+      fail("Should not have reached here");
+    } catch (HoodieIOException ioe) {
+      assertTrue(ioe.getMessage().contains("[timeline-server-based] Failed to 
create marker for partition"));
+    } finally {
+      if (timelineService != null) {
+        timelineService.close();
+      }
+    }
+  }
+
+  static class MockTimelineServerBasedWriteMarkers extends 
TimelineServerBasedWriteMarkers {
+
+    boolean failMarkerCreation = false;
+
+    public MockTimelineServerBasedWriteMarkers(HoodieTable table, String 
instantTime) {

Review Comment:
   This MockTimelineServerBasedWriteMarkers(HoodieTable, String) constructor is 
unused - the test builds the mock through the (String, String, String, 
FileSystemViewStorageConfig) constructor. Remove it.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to