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 =