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

JackieTien97 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 a2c22ac5690 Fix that the initial WAL file is not counted (#17662)
a2c22ac5690 is described below

commit a2c22ac5690ca872616b1bd0f63c7773023f1ee4
Author: Jiang Tian <[email protected]>
AuthorDate: Wed May 13 20:42:18 2026 +0800

    Fix that the initial WAL file is not counted (#17662)
---
 .../dataregion/wal/buffer/AbstractWALBuffer.java   |   2 +
 .../wal/buffer/WALBufferFileNumTest.java           | 202 +++++++++++++++++++++
 2 files changed, 204 insertions(+)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/AbstractWALBuffer.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/AbstractWALBuffer.java
index c8f68523032..c9694c46a2e 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/AbstractWALBuffer.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/AbstractWALBuffer.java
@@ -75,6 +75,8 @@ public abstract class AbstractWALBuffer implements IWALBuffer 
{
                 logDirectory,
                 WALFileUtils.getLogFileName(
                     startFileVersion, currentSearchIndex, 
WALFileStatus.CONTAINS_SEARCH_INDEX)));
+    // count the newly created WAL file into file number statistics
+    addFileNum(1);
     currentWALFileVersion = startFileVersion;
   }
 
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/WALBufferFileNumTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/WALBufferFileNumTest.java
new file mode 100644
index 00000000000..9069473f121
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/WALBufferFileNumTest.java
@@ -0,0 +1,202 @@
+/*
+ * 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.iotdb.db.storageengine.dataregion.wal.buffer;
+
+import org.apache.iotdb.commons.exception.IllegalPathException;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.commons.queryengine.plan.planner.plan.node.PlanNodeId;
+import org.apache.iotdb.consensus.ConsensusFactory;
+import org.apache.iotdb.db.conf.IoTDBConfig;
+import org.apache.iotdb.db.conf.IoTDBDescriptor;
+import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertTabletNode;
+import org.apache.iotdb.db.storageengine.dataregion.wal.WALManager;
+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.storageengine.dataregion.wal.utils.WALMode;
+import org.apache.iotdb.db.utils.EnvironmentUtils;
+import org.apache.iotdb.db.utils.constant.TestConstant;
+
+import org.apache.tsfile.common.conf.TSFileConfig;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.utils.Binary;
+import org.apache.tsfile.utils.BitMap;
+import org.apache.tsfile.write.schema.MeasurementSchema;
+import org.awaitility.Awaitility;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+
+import java.io.File;
+import java.util.Collections;
+
+import static org.junit.Assert.assertEquals;
+
+/** Tests that WAL file number statistics correctly account for all WAL files. 
*/
+public class WALBufferFileNumTest {
+  private static final IoTDBConfig config = 
IoTDBDescriptor.getInstance().getConfig();
+  private static final String identifier = String.valueOf(Integer.MAX_VALUE);
+  private static final String logDirectory =
+      TestConstant.BASE_OUTPUT_PATH.concat("wal-file-num-test");
+  private static final String devicePath = "root.test_sg.test_d";
+
+  private WALMode prevMode;
+  private String prevConsensus;
+  private long prevWalFileSizeThreshold;
+  private WALNode walNode;
+
+  @Before
+  public void setUp() throws Exception {
+    EnvironmentUtils.cleanDir(logDirectory);
+    prevMode = config.getWalMode();
+    prevConsensus = config.getDataRegionConsensusProtocolClass();
+    prevWalFileSizeThreshold = config.getWalFileSizeThresholdInByte();
+    config.setWalMode(WALMode.SYNC);
+    
config.setDataRegionConsensusProtocolClass(ConsensusFactory.RATIS_CONSENSUS);
+    // use a small threshold so that writes can trigger auto-roll
+    config.setWalFileSizeThresholdInByte(2 * 1024 * 1024);
+  }
+
+  @After
+  public void tearDown() throws Exception {
+    if (walNode != null) {
+      walNode.close();
+    }
+    config.setWalMode(prevMode);
+    config.setDataRegionConsensusProtocolClass(prevConsensus);
+    config.setWalFileSizeThresholdInByte(prevWalFileSizeThreshold);
+    EnvironmentUtils.cleanDir(logDirectory);
+  }
+
+  /** Verify that the initial WAL file writer created in the constructor is 
counted in fileNum. */
+  @Test
+  public void testInitialFileNumAfterConstruction() throws Exception {
+    walNode = new WALNode(identifier, logDirectory);
+    // after construction on a fresh directory, there should be exactly 1 WAL 
file
+    // (the currentWALFileWriter created in the constructor)
+    assertEquals(1, walNode.getFileNum());
+    // verify disk agrees
+    File[] walFilesOnDisk = WALFileUtils.listAllWALFiles(new 
File(logDirectory));
+    assertEquals(1, walFilesOnDisk.length);
+  }
+
+  /**
+   * Verify that fileNum stays correct after rolling the WAL file. After one 
roll, there should be 2
+   * files: the original (now closed) and the new writer.
+   */
+  @Test
+  public void testFileNumAfterRoll() throws Exception {
+    walNode = new WALNode(identifier, logDirectory);
+    assertEquals(1, walNode.getFileNum());
+
+    // write some data then roll
+    walNode.log(
+        0,
+        getInsertTabletNode(devicePath, new long[] {1}),
+        Collections.singletonList(new int[] {0, 1}));
+    walNode.rollWALFile();
+    Awaitility.await().until(() -> walNode.isAllWALEntriesConsumed());
+
+    // after one roll: 1 closed file + 1 new open file = 2
+    assertEquals(2, walNode.getFileNum());
+    File[] walFilesOnDisk = WALFileUtils.listAllWALFiles(new 
File(logDirectory));
+    assertEquals(2, walFilesOnDisk.length);
+  }
+
+  /**
+   * Verify that fileNum stays correct after multiple rolls. After N rolls, 
there should be N+1
+   * files on disk and fileNum should match.
+   */
+  @Test
+  public void testFileNumAfterMultipleRolls() throws Exception {
+    walNode = new WALNode(identifier, logDirectory);
+    assertEquals(1, walNode.getFileNum());
+
+    int rollCount = 3;
+    for (int i = 0; i < rollCount; i++) {
+      walNode.log(
+          0,
+          getInsertTabletNode(devicePath, new long[] {i + 1}),
+          Collections.singletonList(new int[] {0, 1}));
+      walNode.rollWALFile();
+      Awaitility.await().until(() -> walNode.isAllWALEntriesConsumed());
+    }
+
+    // rollCount closed files + 1 current open file
+    long expectedFileNum = rollCount + 1;
+    assertEquals(expectedFileNum, walNode.getFileNum());
+    File[] walFilesOnDisk = WALFileUtils.listAllWALFiles(new 
File(logDirectory));
+    assertEquals(expectedFileNum, walFilesOnDisk.length);
+  }
+
+  /**
+   * Verify that WALManager's totalFileNum is consistent with the per-node 
fileNum for a single WAL
+   * node.
+   */
+  @Test
+  public void testTotalFileNumInWALManager() throws Exception {
+    long totalFileNumBefore = WALManager.getInstance().getTotalFileNum();
+    walNode = new WALNode(identifier, logDirectory);
+
+    // after construction, totalFileNum should increase by 1
+    assertEquals(totalFileNumBefore + 1, 
WALManager.getInstance().getTotalFileNum());
+
+    // roll once
+    walNode.log(
+        0,
+        getInsertTabletNode(devicePath, new long[] {1}),
+        Collections.singletonList(new int[] {0, 1}));
+    walNode.rollWALFile();
+    Awaitility.await().until(() -> walNode.isAllWALEntriesConsumed());
+
+    // after one roll, totalFileNum should increase by 1 more
+    assertEquals(totalFileNumBefore + 2, 
WALManager.getInstance().getTotalFileNum());
+  }
+
+  private InsertTabletNode getInsertTabletNode(String devicePath, long[] times)
+      throws IllegalPathException {
+    TSDataType[] dataTypes = new TSDataType[] {TSDataType.TEXT};
+    String[] measurements = new String[] {"s1"};
+    MeasurementSchema[] schemas =
+        new MeasurementSchema[] {new MeasurementSchema("s1", TSDataType.TEXT)};
+
+    Object[] columns = new Object[1];
+    Binary[] binaryValues = new Binary[times.length];
+    for (int i = 0; i < times.length; i++) {
+      binaryValues[i] = new Binary("test" + times[i], 
TSFileConfig.STRING_CHARSET);
+    }
+    columns[0] = binaryValues;
+
+    BitMap[] bitMaps = new BitMap[1];
+    bitMaps[0] = new BitMap(times.length);
+
+    InsertTabletNode node =
+        new InsertTabletNode(
+            new PlanNodeId(""),
+            new PartialPath(devicePath),
+            false,
+            measurements,
+            dataTypes,
+            times,
+            bitMaps,
+            columns,
+            times.length);
+    node.setMeasurementSchemas(schemas);
+    return node;
+  }
+}

Reply via email to