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

Jackie-Jiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/pinot.git


The following commit(s) were added to refs/heads/master by this push:
     new 42cd1d67b6f Tolerate concurrent deletes when sizing consumer and 
segment directories (#19580)
42cd1d67b6f is described below

commit 42cd1d67b6f081bbdfa75963cf9e50204da2037e
Author: Xiaotian (Jackie) Jiang <[email protected]>
AuthorDate: Wed Sep 16 16:13:23 2026 -0700

    Tolerate concurrent deletes when sizing consumer and segment directories 
(#19580)
---
 .../org/apache/pinot/common/utils/FileUtils.java   | 22 ++++++++++++++++++++++
 .../segment/store/SegmentLocalFSDirectory.java     |  8 ++------
 .../server/starter/helix/BaseServerStarter.java    |  3 ++-
 3 files changed, 26 insertions(+), 7 deletions(-)

diff --git 
a/pinot-common/src/main/java/org/apache/pinot/common/utils/FileUtils.java 
b/pinot-common/src/main/java/org/apache/pinot/common/utils/FileUtils.java
index d053d6375ec..2a7873d9e1f 100644
--- a/pinot-common/src/main/java/org/apache/pinot/common/utils/FileUtils.java
+++ b/pinot-common/src/main/java/org/apache/pinot/common/utils/FileUtils.java
@@ -133,4 +133,26 @@ public class FileUtils {
       }
     }
   }
+
+  /// Returns the total size in bytes of the regular files under `dir`, or `0` 
if `dir` does not exist. Symbolic links
+  /// are not followed.
+  ///
+  /// Use this for a directory that another thread may be writing to while it 
is measured. It walks with the `File`
+  /// API, whose `listFiles()` and `length()` report a concurrently deleted 
entry as `null` / `0` instead of throwing,
+  /// so a delete racing with the walk cannot fail the whole computation. The 
trade-off is that an unreadable directory
+  /// is also counted as `0`. For a directory nothing else is writing to, 
prefer
+  /// `org.apache.commons.io.FileUtils#sizeOfDirectory` so that a genuine I/O 
error surfaces.
+  public static long sizeOfDirectory(File dir) {
+    long size = 0;
+    File[] files = dir.listFiles();
+    if (files != null) {
+      for (File file : files) {
+        if (Files.isSymbolicLink(file.toPath())) {
+          continue;
+        }
+        size += file.isDirectory() ? sizeOfDirectory(file) : file.length();
+      }
+    }
+    return size;
+  }
 }
diff --git 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/store/SegmentLocalFSDirectory.java
 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/store/SegmentLocalFSDirectory.java
index b454765d634..2f0338ed36a 100644
--- 
a/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/store/SegmentLocalFSDirectory.java
+++ 
b/pinot-segment-local/src/main/java/org/apache/pinot/segment/local/segment/store/SegmentLocalFSDirectory.java
@@ -182,12 +182,8 @@ public class SegmentLocalFSDirectory extends 
SegmentDirectory {
 
     // check that v3 subdirectory exists since the format may not have been 
converted
     if (_segmentDirectory != null && _segmentDirectory.exists()) {
-      try {
-        return FileUtils.sizeOfDirectory(_segmentDirectory.toPath().toFile());
-      } catch (IllegalArgumentException e) {
-        LOGGER.error("Failed to read disk size for directory: {}", 
_segmentDirectory.getAbsolutePath());
-        return -1;
-      }
+      // A concurrent reload may be rewriting this directory in place, so use 
the delete-tolerant walk.
+      return 
org.apache.pinot.common.utils.FileUtils.sizeOfDirectory(_segmentDirectory);
     } else {
       if (!SegmentDirectoryPaths.isV3Directory(_segmentDirectory)) {
         LOGGER
diff --git 
a/pinot-server/src/main/java/org/apache/pinot/server/starter/helix/BaseServerStarter.java
 
b/pinot-server/src/main/java/org/apache/pinot/server/starter/helix/BaseServerStarter.java
index 24cd13f3baa..d43a54b0c64 100644
--- 
a/pinot-server/src/main/java/org/apache/pinot/server/starter/helix/BaseServerStarter.java
+++ 
b/pinot-server/src/main/java/org/apache/pinot/server/starter/helix/BaseServerStarter.java
@@ -39,7 +39,6 @@ import java.util.function.Supplier;
 import javax.annotation.Nullable;
 import javax.net.ssl.SSLContext;
 import nl.altindag.ssl.SSLFactory;
-import org.apache.commons.io.FileUtils;
 import org.apache.commons.lang3.StringUtils;
 import org.apache.helix.HelixAdmin;
 import org.apache.helix.HelixDataAccessor;
@@ -68,6 +67,7 @@ import org.apache.pinot.common.metrics.ServerMeter;
 import org.apache.pinot.common.metrics.ServerMetrics;
 import org.apache.pinot.common.metrics.ServerTimer;
 import org.apache.pinot.common.restlet.resources.SystemResourceInfo;
+import org.apache.pinot.common.utils.FileUtils;
 import org.apache.pinot.common.utils.PinotAppConfigs;
 import org.apache.pinot.common.utils.ServiceStartableUtils;
 import org.apache.pinot.common.utils.ServiceStatus;
@@ -940,6 +940,7 @@ public abstract class BaseServerStarter implements 
ServiceStartable {
       try {
         for (File consumerDir : instanceConsumerDirs) {
           if (consumerDir.exists()) {
+            // Consuming segments write to this directory continuously, so use 
the delete-tolerant walk.
             totalSize += FileUtils.sizeOfDirectory(consumerDir);
           }
         }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to