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

jackie 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 d40655cf05 Add sanity checks to ensure write permissions for data dir 
(#15876)
d40655cf05 is described below

commit d40655cf05d1bed353ebb30e0cbd04c49540f9b6
Author: Nihal Jain <[email protected]>
AuthorDate: Tue Jun 3 03:33:56 2025 +0530

    Add sanity checks to ensure write permissions for data dir (#15876)
    
    * Add sanity checks to ensure write permissions for instance data and 
segment tar directories (#15860)
    
    * Add unit tests
    
    * Address review comments
---
 .../starter/helix/HelixInstanceDataManager.java    |  21 +++-
 .../helix/HelixInstanceDataManagerTest.java        | 119 +++++++++++++++++++++
 2 files changed, 136 insertions(+), 4 deletions(-)

diff --git 
a/pinot-server/src/main/java/org/apache/pinot/server/starter/helix/HelixInstanceDataManager.java
 
b/pinot-server/src/main/java/org/apache/pinot/server/starter/helix/HelixInstanceDataManager.java
index c71321b6d1..07da49bb5f 100644
--- 
a/pinot-server/src/main/java/org/apache/pinot/server/starter/helix/HelixInstanceDataManager.java
+++ 
b/pinot-server/src/main/java/org/apache/pinot/server/starter/helix/HelixInstanceDataManager.java
@@ -18,6 +18,7 @@
  */
 package org.apache.pinot.server.starter.helix;
 
+import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Preconditions;
 import com.google.common.cache.Cache;
 import com.google.common.cache.CacheBuilder;
@@ -134,9 +135,7 @@ public class HelixInstanceDataManager implements 
InstanceDataManager {
     initInstanceDataDir(instanceDataDir);
 
     File instanceSegmentTarDir = new 
File(_instanceDataManagerConfig.getInstanceSegmentTarDir());
-    if (!instanceSegmentTarDir.exists()) {
-      Preconditions.checkState(instanceSegmentTarDir.mkdirs());
-    }
+    initInstanceSegmentTarDir(instanceSegmentTarDir);
 
     // Initialize segment build time lease extender executor
     SegmentBuildTimeLeaseExtender.initExecutor();
@@ -164,7 +163,8 @@ public class HelixInstanceDataManager implements 
InstanceDataManager {
         
.expireAfterWrite(_instanceDataManagerConfig.getDeletedTablesCacheTtlMinutes(), 
TimeUnit.MINUTES).build();
   }
 
-  private void initInstanceDataDir(File instanceDataDir) {
+  @VisibleForTesting
+  void initInstanceDataDir(File instanceDataDir) {
     if (!instanceDataDir.exists()) {
       Preconditions.checkState(instanceDataDir.mkdirs(), "Failed to create 
instance data dir: %s", instanceDataDir);
     } else {
@@ -188,6 +188,19 @@ public class HelixInstanceDataManager implements 
InstanceDataManager {
         }
       }
     }
+    // Ensure we can write to the instance data dir
+    Preconditions.checkState(instanceDataDir.canWrite(), "Cannot write to the 
instance data dir: %s", instanceDataDir);
+  }
+
+  @VisibleForTesting
+  void initInstanceSegmentTarDir(File instanceSegmentTarDir) {
+    if (!instanceSegmentTarDir.exists()) {
+      Preconditions.checkState(instanceSegmentTarDir.mkdirs(), "Failed to 
create instance segment tar dir: %s",
+          instanceSegmentTarDir);
+    }
+    // Ensure we can write to the instance segment tar dir
+    Preconditions.checkState(instanceSegmentTarDir.canWrite(), "Cannot write 
to the instance segment tar dir: %s",
+        instanceSegmentTarDir);
   }
 
   @Override
diff --git 
a/pinot-server/src/test/java/org/apache/pinot/server/starter/helix/HelixInstanceDataManagerTest.java
 
b/pinot-server/src/test/java/org/apache/pinot/server/starter/helix/HelixInstanceDataManagerTest.java
new file mode 100644
index 0000000000..4fca90aebc
--- /dev/null
+++ 
b/pinot-server/src/test/java/org/apache/pinot/server/starter/helix/HelixInstanceDataManagerTest.java
@@ -0,0 +1,119 @@
+/**
+ * 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.pinot.server.starter.helix;
+
+import java.io.File;
+import org.apache.commons.io.FileUtils;
+import org.mockito.Mockito;
+import org.testng.annotations.AfterClass;
+import org.testng.annotations.BeforeClass;
+import org.testng.annotations.Test;
+
+import static org.testng.Assert.assertFalse;
+import static org.testng.Assert.assertTrue;
+import static org.testng.Assert.fail;
+
+
+public class HelixInstanceDataManagerTest {
+
+  private HelixInstanceDataManager _helixInstanceDataManager;
+  private File _testInstanceDataDir;
+  private File _testInstanceSegmentTarDir;
+
+  @BeforeClass
+  public void setUp() {
+    _helixInstanceDataManager = Mockito.mock(HelixInstanceDataManager.class);
+    _testInstanceDataDir = new File("testInstanceDataDir");
+    _testInstanceSegmentTarDir = new File("testInstanceSegmentTarDir");
+    
Mockito.doCallRealMethod().when(_helixInstanceDataManager).initInstanceDataDir(_testInstanceDataDir);
+    
Mockito.doCallRealMethod().when(_helixInstanceDataManager).initInstanceSegmentTarDir(_testInstanceSegmentTarDir);
+  }
+
+  @AfterClass
+  public void tearDown() {
+    FileUtils.deleteQuietly(_testInstanceDataDir);
+    FileUtils.deleteQuietly(_testInstanceSegmentTarDir);
+  }
+
+  @Test
+  public void testInitInstanceDataDirCreatesDirectory() {
+    if (_testInstanceDataDir.exists()) {
+      FileUtils.deleteQuietly(_testInstanceDataDir);
+    }
+
+    _helixInstanceDataManager.initInstanceDataDir(_testInstanceDataDir);
+
+    assertTrue(_testInstanceDataDir.exists(), "Instance data directory should 
be created.");
+  }
+
+  @Test
+  public void testInitInstanceDataDirCleansUpTempDirs() {
+    File tableDir = new File(_testInstanceDataDir, "tableA_OFFLINE");
+    assertTrue(tableDir.mkdirs(), "Failed to create temp directory.");
+
+    _helixInstanceDataManager.initInstanceDataDir(_testInstanceDataDir);
+
+    assertFalse(tableDir.exists(), "Temporary directory should be deleted.");
+  }
+
+  @Test
+  public void testInitInstanceDataDirThrowsIfNotWritable() {
+    if (!_testInstanceDataDir.exists()) {
+      assertTrue(_testInstanceDataDir.mkdirs(), "Failed to create test 
directory.");
+    }
+    _testInstanceDataDir.setWritable(false);
+
+    try {
+      _helixInstanceDataManager.initInstanceDataDir(_testInstanceDataDir);
+      fail("Expected IllegalStateException due to non-writable directory.");
+    } catch (IllegalStateException e) {
+      // Expected exception
+    } finally {
+      _testInstanceDataDir.setWritable(true);
+    }
+  }
+
+  @Test
+  public void testInitInstanceSegmentTarDirCreatesDirectory() {
+    if (_testInstanceSegmentTarDir.exists()) {
+      FileUtils.deleteQuietly(_testInstanceSegmentTarDir);
+    }
+
+    
_helixInstanceDataManager.initInstanceSegmentTarDir(_testInstanceSegmentTarDir);
+
+    assertTrue(_testInstanceSegmentTarDir.exists(), "Instance segment tar 
directory should be created.");
+  }
+
+  @Test
+  public void testInitInstanceSegmentTarDirThrowsIfNotWritable() {
+    if (!_testInstanceSegmentTarDir.exists()) {
+      assertTrue(_testInstanceSegmentTarDir.mkdirs(), "Failed to create test 
directory.");
+    }
+    _testInstanceSegmentTarDir.setWritable(false);
+
+    try {
+      
_helixInstanceDataManager.initInstanceSegmentTarDir(_testInstanceSegmentTarDir);
+      fail("Expected IllegalStateException due to non-writable directory.");
+    } catch (IllegalStateException e) {
+      // Expected exception
+    } finally {
+      _testInstanceSegmentTarDir.setWritable(true);
+    }
+  }
+}


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

Reply via email to