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

jt2594838 pushed a commit to branch dev/1.3
in repository https://gitbox.apache.org/repos/asf/iotdb.git


The following commit(s) were added to refs/heads/dev/1.3 by this push:
     new 780540cb87a [To dev/1.3] Optimize pipe tablet memory accounting 
(#18211) (#18220)
780540cb87a is described below

commit 780540cb87af7c1509964ac5f0411adaaafc4794
Author: Caideyipi <[email protected]>
AuthorDate: Thu Jul 16 11:08:32 2026 +0800

    [To dev/1.3] Optimize pipe tablet memory accounting (#18211) (#18220)
---
 .../resource/memory/InsertNodeMemoryEstimator.java |  17 ++-
 .../request/PipeTransferTabletBatchReq.java        |  11 +-
 .../InsertNodeMemoryEstimatorPerformanceTest.java  | 104 +++++++++++++++++
 .../memory/InsertNodeMemoryEstimatorTest.java      |  79 +++++++++++++
 .../pipe/sink/PipeDataNodeThriftRequestTest.java   |  16 +++
 .../PipeTransferTabletBatchReqPerformanceTest.java | 126 +++++++++++++++++++++
 6 files changed, 343 insertions(+), 10 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimator.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimator.java
index 9616777b021..b528850f276 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimator.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimator.java
@@ -190,7 +190,7 @@ public class InsertNodeMemoryEstimator {
   }
 
   private static long sizeOfInsertTabletNode(final InsertTabletNode node) {
-    return sizeOfInsertTabletNode(node, newDeduplicatedObjectSet());
+    return sizeOfInsertTabletNode(node, null);
   }
 
   private static long sizeOfInsertTabletNode(
@@ -205,7 +205,7 @@ public class InsertNodeMemoryEstimator {
   }
 
   private static long sizeOfInsertRowNode(final InsertRowNode node) {
-    return sizeOfInsertRowNode(node, newDeduplicatedObjectSet());
+    return sizeOfInsertRowNode(node, null);
   }
 
   private static long sizeOfInsertRowNode(
@@ -217,7 +217,8 @@ public class InsertNodeMemoryEstimator {
   }
 
   private static long sizeOfInsertRowsNode(final InsertRowsNode node) {
-    final Set<Object> deduplicatedObjects = newDeduplicatedObjectSet();
+    final Set<Object> deduplicatedObjects =
+        newDeduplicatedObjectSetIfNeeded(node.getInsertRowNodeList());
     long size = INSERT_ROWS_NODE_SIZE;
     size += calculateFullInsertNodeSize(node, deduplicatedObjects);
     size += sizeOfInsertRowNodeList(node.getInsertRowNodeList(), 
deduplicatedObjects);
@@ -227,7 +228,8 @@ public class InsertNodeMemoryEstimator {
   }
 
   private static long sizeOfInsertRowsOfOneDeviceNode(final 
InsertRowsOfOneDeviceNode node) {
-    final Set<Object> deduplicatedObjects = newDeduplicatedObjectSet();
+    final Set<Object> deduplicatedObjects =
+        newDeduplicatedObjectSetIfNeeded(node.getInsertRowNodeList());
     long size = INSERT_ROWS_OF_ONE_DEVICE_NODE_SIZE;
     size += calculateFullInsertNodeSize(node, deduplicatedObjects);
     size += sizeOfInsertRowNodeList(node.getInsertRowNodeList(), 
deduplicatedObjects);
@@ -237,7 +239,8 @@ public class InsertNodeMemoryEstimator {
   }
 
   private static long sizeOfInsertMultiTabletsNode(final 
InsertMultiTabletsNode node) {
-    final Set<Object> deduplicatedObjects = newDeduplicatedObjectSet();
+    final Set<Object> deduplicatedObjects =
+        newDeduplicatedObjectSetIfNeeded(node.getInsertTabletNodeList());
     long size = INSERT_MULTI_TABLETS_NODE_SIZE;
     size += calculateFullInsertNodeSize(node, deduplicatedObjects);
     size += sizeOfInsertTabletNodeList(node.getInsertTabletNodeList(), 
deduplicatedObjects);
@@ -705,6 +708,10 @@ public class InsertNodeMemoryEstimator {
     return Collections.newSetFromMap(new IdentityHashMap<>());
   }
 
+  private static Set<Object> newDeduplicatedObjectSetIfNeeded(final List<?> 
children) {
+    return children != null && children.size() > 1 ? 
newDeduplicatedObjectSet() : null;
+  }
+
   private static boolean shouldCountObject(
       final Object object, final Set<Object> deduplicatedObjects) {
     return object != null && (deduplicatedObjects == null || 
deduplicatedObjects.add(object));
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/request/PipeTransferTabletBatchReq.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/request/PipeTransferTabletBatchReq.java
index 266894060dc..289aff117c9 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/request/PipeTransferTabletBatchReq.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/request/PipeTransferTabletBatchReq.java
@@ -130,20 +130,21 @@ public class PipeTransferTabletBatchReq extends 
TPipeTransferReq {
   public static PipeTransferTabletBatchReq fromTPipeTransferReq(
       final TPipeTransferReq transferReq) {
     final PipeTransferTabletBatchReq batchReq = new 
PipeTransferTabletBatchReq();
-    final TabletStringInternPool tabletStringInternPool = new 
TabletStringInternPool();
 
     // Binary req, for rolling upgrading
     ReadWriteIOUtils.readInt(transferReq.body);
 
-    int size = ReadWriteIOUtils.readInt(transferReq.body);
-    for (int i = 0; i < size; ++i) {
+    final int insertNodeCount = ReadWriteIOUtils.readInt(transferReq.body);
+    for (int i = 0; i < insertNodeCount; ++i) {
       batchReq.insertNodeReqs.add(
           PipeTransferTabletInsertNodeReq.toTPipeTransferRawReq(
               (InsertNode) PlanFragment.deserializeHelper(transferReq.body, 
null)));
     }
 
-    size = ReadWriteIOUtils.readInt(transferReq.body);
-    for (int i = 0; i < size; ++i) {
+    final int rawTabletCount = ReadWriteIOUtils.readInt(transferReq.body);
+    final TabletStringInternPool tabletStringInternPool =
+        rawTabletCount > 1 ? new TabletStringInternPool() : null;
+    for (int i = 0; i < rawTabletCount; ++i) {
       batchReq.tabletReqs.add(
           PipeTransferTabletRawReq.toTPipeTransferRawReq(transferReq.body, 
tabletStringInternPool));
     }
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimatorPerformanceTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimatorPerformanceTest.java
new file mode 100644
index 00000000000..1a4fc3f9e8e
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimatorPerformanceTest.java
@@ -0,0 +1,104 @@
+/*
+ * 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.resource.memory;
+
+import org.apache.iotdb.commons.exception.IllegalPathException;
+import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
+import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertTabletNode;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.write.schema.MeasurementSchema;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+public class InsertNodeMemoryEstimatorPerformanceTest {
+
+  private static final String ENABLED_PROPERTY =
+      "iotdb.pipe.insert.node.memory.estimator.perf.enabled";
+  private static final String COLUMNS_PROPERTY =
+      "iotdb.pipe.insert.node.memory.estimator.perf.columns";
+  private static final String WARMUP_ITERATIONS_PROPERTY =
+      "iotdb.pipe.insert.node.memory.estimator.perf.warmup.iterations";
+  private static final String ITERATIONS_PROPERTY =
+      "iotdb.pipe.insert.node.memory.estimator.perf.iterations";
+
+  private static volatile long benchmarkBlackhole;
+
+  @Test
+  public void wideTabletSizeOfBenchmark() throws IllegalPathException {
+    Assume.assumeTrue(
+        String.format(
+            "Manual performance UT. Enable with -D%s=true, optionally tune 
-D%s, -D%s and -D%s.",
+            ENABLED_PROPERTY, COLUMNS_PROPERTY, WARMUP_ITERATIONS_PROPERTY, 
ITERATIONS_PROPERTY),
+        Boolean.getBoolean(ENABLED_PROPERTY));
+
+    final int columnCount = Integer.getInteger(COLUMNS_PROPERTY, 100_000);
+    final int warmupIterations = 
Integer.getInteger(WARMUP_ITERATIONS_PROPERTY, 3);
+    final int iterations = Integer.getInteger(ITERATIONS_PROPERTY, 10);
+    Assert.assertTrue(columnCount > 0);
+    Assert.assertTrue(warmupIterations > 0);
+    Assert.assertTrue(iterations > 0);
+
+    final InsertTabletNode insertTabletNode = 
createWideInsertTabletNode(columnCount);
+    runBenchmark(insertTabletNode, warmupIterations);
+    final long elapsedNanos = runBenchmark(insertTabletNode, iterations);
+
+    Assert.assertTrue(benchmarkBlackhole > 0);
+    System.out.printf(
+        "InsertNode memory estimate benchmark: columns=%d, warmups=%d, 
iterations=%d, %.3f ms/op%n",
+        columnCount,
+        warmupIterations,
+        iterations,
+        elapsedNanos / (double) iterations / 1_000_000.0);
+  }
+
+  private static long runBenchmark(final InsertTabletNode insertTabletNode, 
final int iterations) {
+    final long startTime = System.nanoTime();
+    for (int i = 0; i < iterations; ++i) {
+      benchmarkBlackhole = InsertNodeMemoryEstimator.sizeOf(insertTabletNode);
+    }
+    return System.nanoTime() - startTime;
+  }
+
+  private static InsertTabletNode createWideInsertTabletNode(final int 
columnCount)
+      throws IllegalPathException {
+    final String[] measurements = new String[columnCount];
+    final TSDataType[] dataTypes = new TSDataType[columnCount];
+    final MeasurementSchema[] measurementSchemas = new 
MeasurementSchema[columnCount];
+    for (int i = 0; i < columnCount; ++i) {
+      measurements[i] = "s" + i;
+      dataTypes[i] = TSDataType.INT32;
+      measurementSchemas[i] = new MeasurementSchema(measurements[i], 
TSDataType.INT32);
+    }
+    return new InsertTabletNode(
+        new PlanNodeId("wide-memory-estimator"),
+        new PartialPath("root.sg.d1"),
+        false,
+        measurements,
+        dataTypes,
+        measurementSchemas,
+        new long[] {0L},
+        null,
+        new Object[columnCount],
+        1);
+  }
+}
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimatorTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimatorTest.java
index 58b2756b16f..c1e715c7d1f 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimatorTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/memory/InsertNodeMemoryEstimatorTest.java
@@ -24,6 +24,7 @@ import 
org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.commons.path.PartialPath;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertMultiTabletsNode;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowsNode;
 import 
org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowsOfOneDeviceNode;
@@ -150,6 +151,84 @@ public class InsertNodeMemoryEstimatorTest {
             > InsertNodeMemoryEstimator.sizeOf(shortPlanNodeIdRow));
   }
 
+  @Test
+  public void testLeafNodesDoNotDeduplicateRepeatedMeasurementSchemas()
+      throws IllegalPathException {
+    assertLeafNodeDoesNotDeduplicateRepeatedMeasurementSchemas(
+        createTextInsertRowNode(
+            "row", "root.sg.d1", new String[] {"s0", "s1"}, new String[] 
{"v0", "v1"}));
+    assertLeafNodeDoesNotDeduplicateRepeatedMeasurementSchemas(
+        createTextInsertTabletNode("tablet", "root.sg.d1", 2, 1, 1));
+  }
+
+  @Test
+  public void 
testSingleChildCompositesDoNotDeduplicateRepeatedMeasurementSchemas()
+      throws IllegalPathException {
+    final InsertRowNode rowWithDistinctSchemas =
+        createTextInsertRowNode(
+            "row", "root.sg.d1", new String[] {"s0", "s1"}, new String[] 
{"v0", "v1"});
+    final InsertRowNode rowWithRepeatedSchema =
+        createTextInsertRowNode(
+            "row", "root.sg.d1", new String[] {"s0", "s1"}, new String[] 
{"v0", "v1"});
+    replaceSecondSchemaWithEquivalentDistinctSchema(rowWithDistinctSchemas);
+    rowWithRepeatedSchema.getMeasurementSchemas()[1] =
+        rowWithRepeatedSchema.getMeasurementSchemas()[0];
+    Assert.assertEquals(
+        InsertNodeMemoryEstimator.sizeOf(createInsertRowsNode("parent", 
rowWithDistinctSchemas)),
+        InsertNodeMemoryEstimator.sizeOf(createInsertRowsNode("parent", 
rowWithRepeatedSchema)));
+
+    final InsertTabletNode tabletWithDistinctSchemas =
+        createTextInsertTabletNode("tablet", "root.sg.d1", 2, 1, 1);
+    final InsertTabletNode tabletWithRepeatedSchema =
+        createTextInsertTabletNode("tablet", "root.sg.d1", 2, 1, 1);
+    replaceSecondSchemaWithEquivalentDistinctSchema(tabletWithDistinctSchemas);
+    tabletWithRepeatedSchema.getMeasurementSchemas()[1] =
+        tabletWithRepeatedSchema.getMeasurementSchemas()[0];
+    Assert.assertEquals(
+        InsertNodeMemoryEstimator.sizeOf(
+            createInsertMultiTabletsNode("parent", tabletWithDistinctSchemas)),
+        InsertNodeMemoryEstimator.sizeOf(
+            createInsertMultiTabletsNode("parent", tabletWithRepeatedSchema)));
+  }
+
+  @Test
+  public void testMultiChildCompositeDeduplicatesSharedMeasurementSchemas()
+      throws IllegalPathException {
+    final long sizeWithDistinctSchemas =
+        InsertNodeMemoryEstimator.sizeOf(
+            createInsertMultiTabletsNode(
+                "parent",
+                createTextInsertTabletNode("tablet-1", "root.sg.d1", 2, 1, 1),
+                createTextInsertTabletNode("tablet-2", "root.sg.d2", 2, 1, 
1)));
+
+    final InsertTabletNode firstTablet =
+        createTextInsertTabletNode("tablet-1", "root.sg.d1", 2, 1, 1);
+    final InsertTabletNode secondTablet =
+        createTextInsertTabletNode("tablet-2", "root.sg.d2", 2, 1, 1);
+    secondTablet.setMeasurementSchemas(firstTablet.getMeasurementSchemas());
+
+    Assert.assertTrue(
+        InsertNodeMemoryEstimator.sizeOf(
+                createInsertMultiTabletsNode("parent", firstTablet, 
secondTablet))
+            < sizeWithDistinctSchemas);
+  }
+
+  private static void 
assertLeafNodeDoesNotDeduplicateRepeatedMeasurementSchemas(
+      final InsertNode node) {
+    replaceSecondSchemaWithEquivalentDistinctSchema(node);
+    final long sizeWithDistinctSchemas = 
InsertNodeMemoryEstimator.sizeOf(node);
+    node.getMeasurementSchemas()[1] = node.getMeasurementSchemas()[0];
+
+    Assert.assertEquals(sizeWithDistinctSchemas, 
InsertNodeMemoryEstimator.sizeOf(node));
+  }
+
+  private static void replaceSecondSchemaWithEquivalentDistinctSchema(final 
InsertNode node) {
+    final MeasurementSchema firstMeasurementSchema = 
node.getMeasurementSchemas()[0];
+    node.getMeasurementSchemas()[1] =
+        new MeasurementSchema(
+            firstMeasurementSchema.getMeasurementId(), 
firstMeasurementSchema.getType());
+  }
+
   private static InsertRowsNode createInsertRowsNode(
       String planNodeId, InsertRowNode... insertRowNodes) {
     InsertRowsNode node = new InsertRowsNode(new PlanNodeId(planNodeId));
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/PipeDataNodeThriftRequestTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/PipeDataNodeThriftRequestTest.java
index 1dae3b55f97..95f1cdd146c 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/PipeDataNodeThriftRequestTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/PipeDataNodeThriftRequestTest.java
@@ -359,6 +359,22 @@ public class PipeDataNodeThriftRequestTest {
     Assert.assertFalse(deserializedReq.getTabletReqs().get(0).getIsAligned());
   }
 
+  @Test
+  public void 
testPipeTransferTabletBatchReqSkipsStringInterningForSingleRawTablet()
+      throws IOException {
+    final PipeTransferTabletBatchReq deserializedReq =
+        PipeTransferTabletBatchReq.fromTPipeTransferReq(
+            PipeTransferTabletBatchReq.toTPipeTransferReq(
+                Collections.emptyList(),
+                Collections.singletonList(
+                    serializeTablet(
+                        createSingleValueTablet(new String("s1"), new 
String("s1")), false))));
+
+    final Tablet tablet = deserializedReq.getTabletReqs().get(0).getTablet();
+    Assert.assertEquals(tablet.deviceId, 
tablet.getSchemas().get(0).getMeasurementId());
+    Assert.assertNotSame(tablet.deviceId, 
tablet.getSchemas().get(0).getMeasurementId());
+  }
+
   @Test
   public void testPipeTransferTabletBatchReqInternsRepeatedMeasurementNames() 
throws IOException {
     final List<ByteBuffer> tabletBuffers = new ArrayList<>();
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/request/PipeTransferTabletBatchReqPerformanceTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/request/PipeTransferTabletBatchReqPerformanceTest.java
new file mode 100644
index 00000000000..69473573b53
--- /dev/null
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/sink/payload/evolvable/request/PipeTransferTabletBatchReqPerformanceTest.java
@@ -0,0 +1,126 @@
+/*
+ * 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.request;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.utils.PublicBAOS;
+import org.apache.tsfile.utils.ReadWriteIOUtils;
+import org.apache.tsfile.write.record.Tablet;
+import org.apache.tsfile.write.schema.MeasurementSchema;
+import org.junit.Assert;
+import org.junit.Assume;
+import org.junit.Test;
+
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+
+public class PipeTransferTabletBatchReqPerformanceTest {
+
+  private static final String ENABLED_PROPERTY = 
"iotdb.pipe.tablet.batch.deserialize.perf.enabled";
+  private static final String COLUMNS_PROPERTY = 
"iotdb.pipe.tablet.batch.deserialize.perf.columns";
+  private static final String WARMUP_ITERATIONS_PROPERTY =
+      "iotdb.pipe.tablet.batch.deserialize.perf.warmup.iterations";
+  private static final String ITERATIONS_PROPERTY =
+      "iotdb.pipe.tablet.batch.deserialize.perf.iterations";
+
+  private static volatile PipeTransferTabletBatchReq benchmarkBlackhole;
+
+  @Test
+  public void singleWideRawTabletDeserializationBenchmark() throws IOException 
{
+    Assume.assumeTrue(
+        String.format(
+            "Manual performance UT. Enable with -D%s=true, optionally tune 
-D%s, -D%s and -D%s.",
+            ENABLED_PROPERTY, COLUMNS_PROPERTY, WARMUP_ITERATIONS_PROPERTY, 
ITERATIONS_PROPERTY),
+        Boolean.getBoolean(ENABLED_PROPERTY));
+
+    final int columnCount = Integer.getInteger(COLUMNS_PROPERTY, 100_000);
+    final int warmupIterations = 
Integer.getInteger(WARMUP_ITERATIONS_PROPERTY, 1);
+    final int iterations = Integer.getInteger(ITERATIONS_PROPERTY, 5);
+    Assert.assertTrue(columnCount > 0);
+    Assert.assertTrue(warmupIterations >= 0);
+    Assert.assertTrue(iterations > 0);
+
+    final PipeTransferTabletBatchReq request = 
createSingleWideRawTabletBatch(columnCount);
+    final PipeTransferTabletBatchReq verificationResult = deserialize(request);
+    Assert.assertEquals(1, verificationResult.getTabletReqs().size());
+    Assert.assertEquals(
+        columnCount, 
verificationResult.getTabletReqs().get(0).getTablet().getSchemas().size());
+
+    for (int i = 0; i < warmupIterations; ++i) {
+      deserialize(request);
+    }
+
+    final long[] elapsedNanos = new long[iterations];
+    for (int i = 0; i < iterations; ++i) {
+      final long startTime = System.nanoTime();
+      deserialize(request);
+      elapsedNanos[i] = System.nanoTime() - startTime;
+    }
+
+    System.out.printf(
+        Locale.ROOT,
+        "Batch V1 single raw tablet deserialization benchmark: columns=%d, 
warmups=%d, iterations=%d, median=%.3f ms/op%n",
+        columnCount,
+        warmupIterations,
+        iterations,
+        median(elapsedNanos) / 1_000_000.0);
+  }
+
+  private static PipeTransferTabletBatchReq 
createSingleWideRawTabletBatch(final int columnCount)
+      throws IOException {
+    final List<MeasurementSchema> schemas = new ArrayList<>(columnCount);
+    for (int i = 0; i < columnCount; ++i) {
+      schemas.add(new MeasurementSchema("s" + i, TSDataType.INT32));
+    }
+
+    final Tablet tablet = new Tablet("root.sg.d", schemas, 1);
+    return PipeTransferTabletBatchReq.toTPipeTransferReq(
+        Collections.emptyList(), 
Collections.singletonList(serializeTablet(tablet)));
+  }
+
+  private static ByteBuffer serializeTablet(final Tablet tablet) throws 
IOException {
+    try (final PublicBAOS byteArrayOutputStream = new PublicBAOS();
+        final DataOutputStream outputStream = new 
DataOutputStream(byteArrayOutputStream)) {
+      tablet.serialize(outputStream);
+      ReadWriteIOUtils.write(false, outputStream);
+      return ByteBuffer.wrap(byteArrayOutputStream.getBuf(), 0, 
byteArrayOutputStream.size());
+    }
+  }
+
+  private static PipeTransferTabletBatchReq deserialize(final 
PipeTransferTabletBatchReq request) {
+    request.body.position(0);
+    benchmarkBlackhole = 
PipeTransferTabletBatchReq.fromTPipeTransferReq(request);
+    return benchmarkBlackhole;
+  }
+
+  private static double median(final long[] values) {
+    Arrays.sort(values);
+    final int middle = values.length / 2;
+    return (values.length & 1) == 1
+        ? values[middle]
+        : values[middle - 1] + (values[middle] - values[middle - 1]) / 2.0;
+  }
+}

Reply via email to