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 119f262ea660..a7780c74c1c1 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 @@ protected AbstractNodeAllocationStrategy() { 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 @@ protected IWALNode createWALNode(String identifier) { } } - 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 523cc73f0f15..b60d83aef9c1 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.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.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 void testRegisterWALNode() throws IllegalPathException { } } + @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 =