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

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


The following commit(s) were added to refs/heads/master by this push:
     new d1302398148 Extend suspicious disk exception recording to 
SyncFailedException and disk-error IOExceptions (#18572)
d1302398148 is described below

commit d1302398148156bb2968692c75d02da641064a3b
Author: shuwenwei <[email protected]>
AuthorDate: Wed Sep 2 19:37:01 2026 +0800

    Extend suspicious disk exception recording to SyncFailedException and 
disk-error IOExceptions (#18572)
---
 .../service/metrics/DataNodeExceptionMetrics.java  | 44 +++++++++++++++++++---
 1 file changed, 38 insertions(+), 6 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/metrics/DataNodeExceptionMetrics.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/metrics/DataNodeExceptionMetrics.java
index 42035ca0c09..8e43753534d 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/metrics/DataNodeExceptionMetrics.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/metrics/DataNodeExceptionMetrics.java
@@ -27,9 +27,15 @@ import org.apache.iotdb.metrics.type.Counter;
 import org.apache.iotdb.metrics.utils.MetricLevel;
 import org.apache.iotdb.metrics.utils.MetricType;
 
+import java.io.IOException;
+import java.io.SyncFailedException;
 import java.nio.file.FileSystemException;
 
-/** Records DataNode exceptions whose cause chain contains a {@link 
FileSystemException}. */
+/**
+ * Records DataNode exceptions whose cause chain contains a suspicious disk 
I/O exception, i.e. an
+ * exact {@link FileSystemException}, a {@link SyncFailedException}, or an 
{@link IOException}
+ * carrying a well-known disk-error message.
+ */
 public class DataNodeExceptionMetrics implements IMetricSet {
 
   private static final DataNodeExceptionMetrics INSTANCE = new 
DataNodeExceptionMetrics();
@@ -54,18 +60,44 @@ public class DataNodeExceptionMetrics implements IMetricSet 
{
   }
 
   public void recordSuspiciousDiskException(Throwable throwable) {
-    // Uses exact type matching instead of instanceof because subclasses of
-    // FileSystemException (e.g. NoSuchFileException, NotDirectoryException,
-    // AccessDeniedException) usually indicate logical file-state errors rather
-    // than real disk failures, so they should not be counted here.
     for (Throwable current = throwable; current != null; current = 
current.getCause()) {
-      if (current.getClass() == FileSystemException.class) {
+      if (isSuspiciousDiskException(current)) {
         suspiciousDiskExceptionCounter.inc();
         return;
       }
     }
   }
 
+  private static boolean isSuspiciousDiskException(Throwable throwable) {
+    // 1) exact FileSystemException. Subclasses (e.g. NoSuchFileException,
+    // NotDirectoryException, AccessDeniedException) usually indicate logical
+    // file-state errors rather than real disk failures, so they are not 
counted here.
+    if (throwable.getClass() == FileSystemException.class) {
+      return true;
+    }
+    // 2) SyncFailedException: fsync/force failure is almost always a real 
disk problem.
+    // Its message is fixed to "Sync failed" without the errno text, so it can 
only be
+    // recognized by its type.
+    if (throwable instanceof SyncFailedException) {
+      return true;
+    }
+    // 3) Plain IOException thrown by reads/writes/force on already-open 
channels carries
+    // the errno text in its message. Match the well-known disk-error messages 
instead of
+    // counting every IOException (EOF, closed stream, etc. are not disk 
problems).
+    if (throwable instanceof IOException) {
+      String message = throwable.getMessage();
+      if (message != null) {
+        return message.contains("Input/output error")
+            || message.contains("No space left on device")
+            || message.contains("Read-only file system")
+            || message.contains("Structure needs cleaning")
+            || message.contains("No such device or address")
+            || message.contains("Disk quota exceeded");
+      }
+    }
+    return false;
+  }
+
   public static DataNodeExceptionMetrics getInstance() {
     return INSTANCE;
   }

Reply via email to