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 bd4945780bb Optimize pipe wide table batch append precheck (#18117)
bd4945780bb is described below

commit bd4945780bb9653d780da9aae44fac517c60621e
Author: Caideyipi <[email protected]>
AuthorDate: Mon Jul 6 16:38:36 2026 +0800

    Optimize pipe wide table batch append precheck (#18117)
---
 .../evolvable/batch/PipeTabletEventPlainBatch.java |  10 +-
 .../PipeTabletEventPlainBatchPerformanceTest.java  | 137 +++++++++++++++++++++
 2 files changed, 142 insertions(+), 5 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/batch/PipeTabletEventPlainBatch.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/batch/PipeTabletEventPlainBatch.java
index 3d76dd857d9..abb9ae26608 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/batch/PipeTabletEventPlainBatch.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/batch/PipeTabletEventPlainBatch.java
@@ -110,7 +110,7 @@ public class PipeTabletEventPlainBatch extends 
PipeTabletEventBatch {
         for (final Tablet tablet : tabletEntry.getValue().getRight()) {
           boolean success = false;
           for (final Pair<Boolean, Tablet> tabletPair : batchTablets) {
-            if (!canAppendTablet(tabletPair.getRight(), tablet)) {
+            if (!mayAppendTablet(tabletPair.getRight(), tablet)) {
               continue;
             }
             if (tabletPair.getLeft()) {
@@ -217,10 +217,10 @@ public class PipeTabletEventPlainBatch extends 
PipeTabletEventBatch {
     return PipeMemoryWeightUtil.calculateTabletSizeInBytes(tablet) + 4;
   }
 
-  private static boolean canAppendTablet(final Tablet target, final Tablet 
source) {
-    return Objects.equals(target.getDeviceId(), source.getDeviceId())
-        && Objects.equals(target.getSchemas(), source.getSchemas())
-        && Objects.equals(target.getColumnTypes(), source.getColumnTypes());
+  static boolean mayAppendTablet(final Tablet target, final Tablet source) {
+    // Tablet.append already checks schemas and column categories. Avoid 
repeating those potentially
+    // expensive comparisons here because wide-table pipe transfer can have 
many columns.
+    return Objects.equals(target.getDeviceId(), source.getDeviceId());
   }
 
   public static Tablet copyTablet(final Tablet tablet) {
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/batch/PipeTabletEventPlainBatchPerformanceTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/batch/PipeTabletEventPlainBatchPerformanceTest.java
new file mode 100644
index 00000000000..eff12e6c818
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/batch/PipeTabletEventPlainBatchPerformanceTest.java
@@ -0,0 +1,137 @@
+/*
+ * 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.pipe.sink.payload.evolvable.batch;
+
+import org.apache.tsfile.enums.ColumnCategory;
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.write.record.Tablet;
+import org.apache.tsfile.write.schema.IMeasurementSchema;
+import org.apache.tsfile.write.schema.MeasurementSchema;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+
+public class PipeTabletEventPlainBatchPerformanceTest {
+
+  private static final String ENABLED_PROPERTY = 
"iotdb.pipe.plain.batch.perf.enabled";
+  private static final String COLUMNS_PROPERTY = 
"iotdb.pipe.plain.batch.perf.columns";
+  private static final String ITERATIONS_PROPERTY = 
"iotdb.pipe.plain.batch.perf.iterations";
+
+  @Test
+  public void wideTableMayAppendTabletBenchmark() {
+    Assume.assumeTrue(
+        String.format(
+            "Manual performance UT. Enable with -D%s=true, optionally tune 
-D%s and -D%s.",
+            ENABLED_PROPERTY, COLUMNS_PROPERTY, ITERATIONS_PROPERTY),
+        Boolean.getBoolean(ENABLED_PROPERTY));
+
+    final int columnCount = Integer.getInteger(COLUMNS_PROPERTY, 100_000);
+    final int iterations = Integer.getInteger(ITERATIONS_PROPERTY, 1_000);
+    final int warmupIterations = Math.max(10, Math.min(iterations, 200));
+
+    final Tablet target = createWideTableModelTablet("table1", columnCount);
+    final Tablet source = createWideTableModelTablet("table1", columnCount);
+
+    runLegacyPrecheck(target, source, warmupIterations);
+    runOptimizedPrecheck(target, source, warmupIterations);
+
+    final BenchmarkResult legacyResult = runLegacyPrecheck(target, source, 
iterations);
+    final BenchmarkResult optimizedResult = runOptimizedPrecheck(target, 
source, iterations);
+
+    Assert.assertEquals(iterations, legacyResult.getSuccessCount());
+    Assert.assertEquals(iterations, optimizedResult.getSuccessCount());
+
+    System.out.printf(
+        "Wide-table tablet append precheck benchmark: columns=%d, 
iterations=%d, legacy=%.3f ms, optimized=%.3f ms, speedup=%.2fx%n",
+        columnCount,
+        iterations,
+        toMillis(legacyResult.getElapsedNanos()),
+        toMillis(optimizedResult.getElapsedNanos()),
+        (double) legacyResult.getElapsedNanos() / 
optimizedResult.getElapsedNanos());
+  }
+
+  private static BenchmarkResult runLegacyPrecheck(
+      final Tablet target, final Tablet source, final int iterations) {
+    int successCount = 0;
+    final long startTime = System.nanoTime();
+    for (int i = 0; i < iterations; ++i) {
+      if (legacyCanAppendTablet(target, source)) {
+        ++successCount;
+      }
+    }
+    return new BenchmarkResult(System.nanoTime() - startTime, successCount);
+  }
+
+  private static BenchmarkResult runOptimizedPrecheck(
+      final Tablet target, final Tablet source, final int iterations) {
+    int successCount = 0;
+    final long startTime = System.nanoTime();
+    for (int i = 0; i < iterations; ++i) {
+      if (PipeTabletEventPlainBatch.mayAppendTablet(target, source)) {
+        ++successCount;
+      }
+    }
+    return new BenchmarkResult(System.nanoTime() - startTime, successCount);
+  }
+
+  private static boolean legacyCanAppendTablet(final Tablet target, final 
Tablet source) {
+    return Objects.equals(target.getDeviceId(), source.getDeviceId())
+        && Objects.equals(target.getSchemas(), source.getSchemas())
+        && Objects.equals(target.getColumnTypes(), source.getColumnTypes());
+  }
+
+  private static Tablet createWideTableModelTablet(final String tableName, 
final int columnCount) {
+    final List<IMeasurementSchema> schemas = new ArrayList<>(columnCount);
+    final List<ColumnCategory> columnCategories = new ArrayList<>(columnCount);
+    for (int i = 0; i < columnCount; ++i) {
+      schemas.add(new MeasurementSchema("s" + i, TSDataType.INT32));
+      columnCategories.add(ColumnCategory.FIELD);
+    }
+    return new Tablet(
+        tableName, schemas, columnCategories, new long[] {0L}, new 
Object[columnCount], null, 1);
+  }
+
+  private static double toMillis(final long nanos) {
+    return nanos / 1_000_000.0;
+  }
+
+  private static class BenchmarkResult {
+
+    private final long elapsedNanos;
+    private final int successCount;
+
+    private BenchmarkResult(final long elapsedNanos, final int successCount) {
+      this.elapsedNanos = elapsedNanos;
+      this.successCount = successCount;
+    }
+
+    private long getElapsedNanos() {
+      return elapsedNanos;
+    }
+
+    private int getSuccessCount() {
+      return successCount;
+    }
+  }
+}

Reply via email to