hudi-agent commented on code in PR #19494:
URL: https://github.com/apache/hudi/pull/19494#discussion_r3712694250


##########
hudi-common/src/main/java/org/apache/hudi/common/model/HoodiePartitionMetadata.java:
##########
@@ -106,22 +106,37 @@ public void trySave() throws HoodieIOException {
     RetryHelper<Void, HoodieIOException>  retryHelper = new RetryHelper(1000, 
3, 1000, HoodieIOException.class.getName())
         .tryWith(() -> {
           if (!storage.exists(metaPath)) {
-            if (format.isPresent()) {
-              writeMetafileInFormat(metaPath, format.get());
-            } else {
-              // Backwards compatible properties file format
-              try (ByteArrayOutputStream os = new ByteArrayOutputStream()) {
-                props.store(os, "partition metadata");
-                Option<byte []> content = Option.of(os.toByteArray());
-                storage.createImmutableFileInPath(metaPath, 
content.map(HoodieInstantWriter::convertByteArrayToWriter));
+            try {
+              writeMetafile(metaPath);
+            } catch (IOException | HoodieIOException e) {
+              // The metafile is immutable, so tasks writing to the same 
partition concurrently race
+              // to create it and all but the winner fail with an 'already 
exists' error. Losing that
+              // race means the metafile is in place, which is what the caller 
asked for: retrying
+              // would only re-observe the same file, and warning about it is 
pure noise.
+              if (!storage.exists(metaPath)) {

Review Comment:
   🤖 This re-check `storage.exists(metaPath)` can itself throw `IOException` 
(e.g. transient throttling on an object store — plausible right when the write 
just failed transiently). If it throws, the original `e` is lost and a raw 
`IOException` propagates instead. That new exception isn't in this 
RetryHelper's retry list (only `HoodieIOException` is), so the original 
retryable write failure no longer gets retried, and a checked `IOException` can 
slip past callers that catch only `HoodieIOException`. Would it be safer to 
rethrow the original `e` when the existence re-check fails, so a genuine 
transient write error still flows through the normal retry path?
   
   <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag 
quality.</i></sub>



##########
hudi-common/src/test/java/org/apache/hudi/common/util/TestRetryHelper.java:
##########
@@ -52,6 +61,55 @@ public void testCheckIfExceptionInRetryList() throws 
Exception {
     assertTrue(retry);
   }
 
+  /**
+   * The point of HUDI-9095: a retry that is going to be attempted again must 
not dump a stack trace
+   * into the log. The cause still has to be identifiable from the message 
itself.
+   */
+  @Test
+  public void testRetryWarningCarriesNoStackTrace() {
+    HoodieTestLogAppender appender = new 
HoodieTestLogAppender().attachTo(RetryHelper.class);
+    try {
+      AtomicInteger attempts = new AtomicInteger(0);
+      RetryHelper retryHelper = new RetryHelper(INTERVAL_TIME, 3, 
INTERVAL_TIME, (String) null, "save partition metafile");
+      assertDoesNotThrow(() -> retryHelper.start(() -> {
+        if (attempts.incrementAndGet() < 3) {
+          throw new IOException("Failed to create file 
/a/b/.hoodie_partition_metadata",
+              new FileAlreadyExistsException("File already exists: 
/a/b/.hoodie_partition_metadata"));
+        }
+        return true;
+      }));
+
+      List<LogEvent> warnings = appender.getLog().stream()
+          .filter(event -> 
Level.WARN.equals(event.getLevel())).collect(Collectors.toList());
+      assertFalse(warnings.isEmpty(), "the retries should still be reported at 
warn level");
+      for (LogEvent warning : warnings) {
+        assertNull(warning.getThrown(),
+            "the retry warning must not carry a throwable, otherwise the 
logger prints its stack trace");
+        String message = warning.getMessage().getFormattedMessage();
+        assertTrue(message.contains("save partition metafile"), message);
+        assertTrue(message.contains("java.io.IOException: Failed to create 
file /a/b/.hoodie_partition_metadata"), message);
+        assertTrue(message.contains("FileAlreadyExistsException"), "the root 
cause must survive: " + message);
+      }
+    } finally {
+      appender.detach();
+    }
+  }
+
+  @Test

Review Comment:
   🤖 nit: could you rename this to `testSummarizeKeepsRootCauseOnASingleLine` 
to match the spelling of the production method `summarize`? The 
British-vs-American mismatch is a small speed-bump when scanning for which test 
covers which method.
   
   <sub><i>⚠️ AI-generated; verify before applying. React 👍/👎 to flag 
quality.</i></sub>



-- 
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