Skip to content

Commit 1bf79ca

Browse files
Fix folderManager NPE issue in WALNode when starting iotdb in a disk-full state (#16869)
1 parent c77bb57 commit 1bf79ca

File tree

2 files changed

+92
-10
lines changed

2 files changed

+92
-10
lines changed

iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/AbstractNodeAllocationStrategy.java

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,24 @@ protected AbstractNodeAllocationStrategy() {
4949
new FolderManager(
5050
Arrays.asList(commonConfig.getWalDirs()), DirectoryStrategyType.SEQUENCE_STRATEGY);
5151
} catch (DiskSpaceInsufficientException e) {
52+
// folderManager remains null when disk space is insufficient during initialization
53+
// It will be lazily initialized later when disk space becomes available
5254
logger.error(
5355
"Fail to create wal node allocation strategy because all disks of wal folders are full.",
5456
e);
5557
}
5658
}
5759

58-
protected IWALNode createWALNode(String identifier) {
60+
protected synchronized IWALNode createWALNode(String identifier) {
5961
try {
62+
// Lazy initialization of folderManager: if it was null during constructor
63+
// (due to insufficient disk space), try to initialize it now when disk space
64+
// might have become available
65+
if (folderManager == null) {
66+
folderManager =
67+
new FolderManager(
68+
Arrays.asList(commonConfig.getWalDirs()), DirectoryStrategyType.SEQUENCE_STRATEGY);
69+
}
6070
return folderManager.getNextWithRetry(
6171
folder -> new WALNode(identifier, folder + File.separator + identifier));
6272
} catch (DiskSpaceInsufficientException e) {
@@ -70,15 +80,6 @@ protected IWALNode createWALNode(String identifier) {
7080
}
7181
}
7282

73-
protected IWALNode createWALNode(String identifier, String folder) {
74-
try {
75-
return new WALNode(identifier, folder);
76-
} catch (IOException e) {
77-
logger.error("Meet exception when creating wal node", e);
78-
return WALFakeNode.getFailureInstance(e);
79-
}
80-
}
81-
8283
protected IWALNode createWALNode(
8384
String identifier, String folder, long startFileVersion, long startSearchIndex) {
8485
try {

iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/FirstCreateStrategyTest.java

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
2626
import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowNode;
2727
import org.apache.iotdb.db.storageengine.dataregion.wal.node.IWALNode;
28+
import org.apache.iotdb.db.storageengine.dataregion.wal.node.WALNode;
2829
import org.apache.iotdb.db.storageengine.dataregion.wal.utils.WALFileUtils;
2930
import org.apache.iotdb.db.utils.EnvironmentUtils;
3031
import org.apache.iotdb.db.utils.constant.TestConstant;
@@ -38,6 +39,9 @@
3839
import org.junit.Test;
3940

4041
import java.io.File;
42+
import java.io.IOException;
43+
import java.nio.file.Files;
44+
import java.nio.file.Path;
4145

4246
import static org.junit.Assert.assertEquals;
4347
import static org.junit.Assert.assertNotEquals;
@@ -141,6 +145,83 @@ public void testRegisterWALNode() throws IllegalPathException {
141145
}
142146
}
143147

148+
@Test
149+
public void testReInitializeAfterDiskSpaceCleaned() throws IllegalPathException, IOException {
150+
// Create unique temporary directory for testing
151+
Path tempDir = Files.createTempDirectory("iotdb_wal_reinit_test_");
152+
153+
String[] testWalDirs =
154+
new String[] {
155+
tempDir.resolve("wal_reinit_test1").toString(),
156+
tempDir.resolve("wal_reinit_test2").toString(),
157+
tempDir.resolve("wal_reinit_test3").toString()
158+
};
159+
160+
String[] originalWalDirs = commonConfig.getWalDirs();
161+
162+
try {
163+
commonConfig.setWalDirs(testWalDirs);
164+
// Create strategy with valid directories first
165+
FirstCreateStrategy strategy = new FirstCreateStrategy();
166+
167+
// Simulate folderManager becoming null (e.g., due to disk space issues)
168+
// We'll use reflection to set folderManager to null to test re-initialization
169+
try {
170+
java.lang.reflect.Field folderManagerField =
171+
AbstractNodeAllocationStrategy.class.getDeclaredField("folderManager");
172+
folderManagerField.setAccessible(true);
173+
folderManagerField.set(strategy, null);
174+
} catch (NoSuchFieldException | IllegalAccessException e) {
175+
throw new RuntimeException("Failed to set folderManager to null for testing", e);
176+
}
177+
178+
// Now apply for WAL node, should successfully re-initialize folderManager
179+
IWALNode walNode = strategy.applyForWALNode("test_reinit_identifier");
180+
assertNotNull("WAL node should be created after re-initialization", walNode);
181+
182+
// Verify that re-initialization actually occurred - should return WALNode, not WALFakeNode
183+
assertTrue(
184+
"Returned node should be WALNode instance after successful re-initialization",
185+
walNode instanceof WALNode);
186+
187+
// Verify that WAL node was created successfully by logging data
188+
walNode.log(1, getInsertRowNode());
189+
190+
// Verify that WAL files were created in at least one directory
191+
boolean walFileCreated = false;
192+
for (String walDir : testWalDirs) {
193+
File walDirFile = new File(walDir);
194+
if (walDirFile.exists()) {
195+
File[] nodeDirs = walDirFile.listFiles(File::isDirectory);
196+
if (nodeDirs != null && nodeDirs.length > 0) {
197+
for (File nodeDir : nodeDirs) {
198+
if (nodeDir.exists() && WALFileUtils.listAllWALFiles(nodeDir).length > 0) {
199+
walFileCreated = true;
200+
break;
201+
}
202+
}
203+
}
204+
}
205+
if (walFileCreated) {
206+
break;
207+
}
208+
}
209+
assertTrue("WAL files should be created after re-initialization", walFileCreated);
210+
211+
// Clean up
212+
walNode.close();
213+
} finally {
214+
// Clean up the test directories
215+
for (String walDir : testWalDirs) {
216+
EnvironmentUtils.cleanDir(walDir);
217+
}
218+
// Clean up temp directory
219+
EnvironmentUtils.cleanDir(tempDir.toString());
220+
// Restore original WAL directories
221+
commonConfig.setWalDirs(originalWalDirs);
222+
}
223+
}
224+
144225
private InsertRowNode getInsertRowNode() throws IllegalPathException {
145226
long time = 110L;
146227
TSDataType[] dataTypes =

0 commit comments

Comments
 (0)