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

haonan 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 1bf79ca4713 Fix folderManager NPE issue in WALNode when starting iotdb 
in a disk-full state (#16869)
1bf79ca4713 is described below

commit 1bf79ca4713ed9debe2e8c8a9ad6b7607f5a2b25
Author: Potato <[email protected]>
AuthorDate: Tue Dec 16 10:49:38 2025 +0800

    Fix folderManager NPE issue in WALNode when starting iotdb in a disk-full 
state (#16869)
---
 .../allocation/AbstractNodeAllocationStrategy.java | 21 +++---
 .../wal/allocation/FirstCreateStrategyTest.java    | 81 ++++++++++++++++++++++
 2 files changed, 92 insertions(+), 10 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/AbstractNodeAllocationStrategy.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/AbstractNodeAllocationStrategy.java
index 119f262ea66..a7780c74c1c 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/AbstractNodeAllocationStrategy.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/AbstractNodeAllocationStrategy.java
@@ -49,14 +49,24 @@ public abstract class AbstractNodeAllocationStrategy 
implements NodeAllocationSt
           new FolderManager(
               Arrays.asList(commonConfig.getWalDirs()), 
DirectoryStrategyType.SEQUENCE_STRATEGY);
     } catch (DiskSpaceInsufficientException e) {
+      // folderManager remains null when disk space is insufficient during 
initialization
+      // It will be lazily initialized later when disk space becomes available
       logger.error(
           "Fail to create wal node allocation strategy because all disks of 
wal folders are full.",
           e);
     }
   }
 
-  protected IWALNode createWALNode(String identifier) {
+  protected synchronized IWALNode createWALNode(String identifier) {
     try {
+      // Lazy initialization of folderManager: if it was null during 
constructor
+      // (due to insufficient disk space), try to initialize it now when disk 
space
+      // might have become available
+      if (folderManager == null) {
+        folderManager =
+            new FolderManager(
+                Arrays.asList(commonConfig.getWalDirs()), 
DirectoryStrategyType.SEQUENCE_STRATEGY);
+      }
       return folderManager.getNextWithRetry(
           folder -> new WALNode(identifier, folder + File.separator + 
identifier));
     } catch (DiskSpaceInsufficientException e) {
@@ -70,15 +80,6 @@ public abstract class AbstractNodeAllocationStrategy 
implements NodeAllocationSt
     }
   }
 
-  protected IWALNode createWALNode(String identifier, String folder) {
-    try {
-      return new WALNode(identifier, folder);
-    } catch (IOException e) {
-      logger.error("Meet exception when creating wal node", e);
-      return WALFakeNode.getFailureInstance(e);
-    }
-  }
-
   protected IWALNode createWALNode(
       String identifier, String folder, long startFileVersion, long 
startSearchIndex) {
     try {
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/FirstCreateStrategyTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/FirstCreateStrategyTest.java
index 523cc73f0f1..b60d83aef9c 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/FirstCreateStrategyTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/FirstCreateStrategyTest.java
@@ -25,6 +25,7 @@ import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowNode;
 import org.apache.iotdb.db.storageengine.dataregion.wal.node.IWALNode;
+import org.apache.iotdb.db.storageengine.dataregion.wal.node.WALNode;
 import org.apache.iotdb.db.storageengine.dataregion.wal.utils.WALFileUtils;
 import org.apache.iotdb.db.utils.EnvironmentUtils;
 import org.apache.iotdb.db.utils.constant.TestConstant;
@@ -38,6 +39,9 @@ import org.junit.Before;
 import org.junit.Test;
 
 import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
@@ -141,6 +145,83 @@ public class FirstCreateStrategyTest {
     }
   }
 
+  @Test
+  public void testReInitializeAfterDiskSpaceCleaned() throws 
IllegalPathException, IOException {
+    // Create unique temporary directory for testing
+    Path tempDir = Files.createTempDirectory("iotdb_wal_reinit_test_");
+
+    String[] testWalDirs =
+        new String[] {
+          tempDir.resolve("wal_reinit_test1").toString(),
+          tempDir.resolve("wal_reinit_test2").toString(),
+          tempDir.resolve("wal_reinit_test3").toString()
+        };
+
+    String[] originalWalDirs = commonConfig.getWalDirs();
+
+    try {
+      commonConfig.setWalDirs(testWalDirs);
+      // Create strategy with valid directories first
+      FirstCreateStrategy strategy = new FirstCreateStrategy();
+
+      // Simulate folderManager becoming null (e.g., due to disk space issues)
+      // We'll use reflection to set folderManager to null to test 
re-initialization
+      try {
+        java.lang.reflect.Field folderManagerField =
+            
AbstractNodeAllocationStrategy.class.getDeclaredField("folderManager");
+        folderManagerField.setAccessible(true);
+        folderManagerField.set(strategy, null);
+      } catch (NoSuchFieldException | IllegalAccessException e) {
+        throw new RuntimeException("Failed to set folderManager to null for 
testing", e);
+      }
+
+      // Now apply for WAL node, should successfully re-initialize 
folderManager
+      IWALNode walNode = strategy.applyForWALNode("test_reinit_identifier");
+      assertNotNull("WAL node should be created after re-initialization", 
walNode);
+
+      // Verify that re-initialization actually occurred - should return 
WALNode, not WALFakeNode
+      assertTrue(
+          "Returned node should be WALNode instance after successful 
re-initialization",
+          walNode instanceof WALNode);
+
+      // Verify that WAL node was created successfully by logging data
+      walNode.log(1, getInsertRowNode());
+
+      // Verify that WAL files were created in at least one directory
+      boolean walFileCreated = false;
+      for (String walDir : testWalDirs) {
+        File walDirFile = new File(walDir);
+        if (walDirFile.exists()) {
+          File[] nodeDirs = walDirFile.listFiles(File::isDirectory);
+          if (nodeDirs != null && nodeDirs.length > 0) {
+            for (File nodeDir : nodeDirs) {
+              if (nodeDir.exists() && 
WALFileUtils.listAllWALFiles(nodeDir).length > 0) {
+                walFileCreated = true;
+                break;
+              }
+            }
+          }
+        }
+        if (walFileCreated) {
+          break;
+        }
+      }
+      assertTrue("WAL files should be created after re-initialization", 
walFileCreated);
+
+      // Clean up
+      walNode.close();
+    } finally {
+      // Clean up the test directories
+      for (String walDir : testWalDirs) {
+        EnvironmentUtils.cleanDir(walDir);
+      }
+      // Clean up temp directory
+      EnvironmentUtils.cleanDir(tempDir.toString());
+      // Restore original WAL directories
+      commonConfig.setWalDirs(originalWalDirs);
+    }
+  }
+
   private InsertRowNode getInsertRowNode() throws IllegalPathException {
     long time = 110L;
     TSDataType[] dataTypes =

Reply via email to