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

jt2594838 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 e28c4ebce7c Fix ObjectWriter accepting segment offsets beyond EOF 
(#18907)
e28c4ebce7c is described below

commit e28c4ebce7c20546e6d935d793054ae682a4d880
Author: Hongzhi Gao <[email protected]>
AuthorDate: Mon Oct 19 14:00:10 2026 +0800

    Fix ObjectWriter accepting segment offsets beyond EOF (#18907)
---
 .../org/apache/iotdb/db/utils/ObjectWriter.java    |  2 +-
 .../apache/iotdb/db/utils/ObjectWriterTest.java    | 84 ++++++++++++++++++++++
 2 files changed, 85 insertions(+), 1 deletion(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/ObjectWriter.java 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/ObjectWriter.java
index b85b136af61..3bc1f0f9a41 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/ObjectWriter.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/ObjectWriter.java
@@ -66,7 +66,7 @@ public class ObjectWriter implements AutoCloseable {
   public void write(boolean isGeneratedByConsensus, long offset, byte[] 
content)
       throws IOException {
     if (file.length() != offset) {
-      if (isGeneratedByConsensus || offset == 0) {
+      if (offset < file.length() && (isGeneratedByConsensus || offset == 0)) {
         org.apache.iotdb.commons.utils.FileUtils.truncateFile(file, offset);
         channel.position(offset);
       } else {
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/ObjectWriterTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/ObjectWriterTest.java
new file mode 100644
index 00000000000..0dc6fdf3b2f
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/utils/ObjectWriterTest.java
@@ -0,0 +1,84 @@
+/*
+ * 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.utils;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.file.Files;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertThrows;
+
+public class ObjectWriterTest {
+
+  @Rule public final TemporaryFolder temporaryFolder = new TemporaryFolder();
+
+  @Test
+  public void testRejectMissingSegments() throws Exception {
+    for (boolean isGeneratedByConsensus : new boolean[] {false, true}) {
+      File file = temporaryFolder.newFile();
+      try (ObjectWriter writer = new ObjectWriter(file)) {
+        // The first segment is missing.
+        assertThrows(
+            IOException.class, () -> writer.write(isGeneratedByConsensus, 2, 
new byte[] {3, 4}));
+        assertArrayEquals(new byte[0], Files.readAllBytes(file.toPath()));
+
+        writer.write(isGeneratedByConsensus, 0, new byte[] {1, 2});
+        // The middle segment is missing.
+        assertThrows(
+            IOException.class, () -> writer.write(isGeneratedByConsensus, 4, 
new byte[] {5, 6}));
+        assertArrayEquals(new byte[] {1, 2}, 
Files.readAllBytes(file.toPath()));
+
+        writer.write(isGeneratedByConsensus, 2, new byte[] {3, 4});
+        writer.write(isGeneratedByConsensus, 4, new byte[] {5, 6});
+        assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6}, 
Files.readAllBytes(file.toPath()));
+      }
+    }
+  }
+
+  @Test
+  public void testRewriteAfterReopen() throws Exception {
+    File file = temporaryFolder.newFile();
+    try (ObjectWriter writer = new ObjectWriter(file)) {
+      writer.write(false, 0, new byte[] {1, 2, 3, 4, 5, 6});
+    }
+    try (ObjectWriter writer = new ObjectWriter(file)) {
+      assertThrows(IOException.class, () -> writer.write(false, 2, new byte[] 
{7}));
+      assertArrayEquals(new byte[] {1, 2, 3, 4, 5, 6}, 
Files.readAllBytes(file.toPath()));
+
+      writer.write(true, 2, new byte[] {7});
+      assertArrayEquals(new byte[] {1, 2, 7}, 
Files.readAllBytes(file.toPath()));
+      writer.write(true, 3, new byte[] {8});
+      assertArrayEquals(new byte[] {1, 2, 7, 8}, 
Files.readAllBytes(file.toPath()));
+    }
+    for (boolean isGeneratedByConsensus : new boolean[] {false, true}) {
+      try (ObjectWriter writer = new ObjectWriter(file)) {
+        writer.write(isGeneratedByConsensus, 0, new byte[] {9});
+        assertArrayEquals(new byte[] {9}, Files.readAllBytes(file.toPath()));
+        writer.write(isGeneratedByConsensus, 1, new byte[] {10, 11});
+        assertArrayEquals(new byte[] {9, 10, 11}, 
Files.readAllBytes(file.toPath()));
+      }
+    }
+  }
+}

Reply via email to