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

WangzJi pushed a commit to branch 2.x
in repository https://gitbox.apache.org/repos/asf/incubator-seata.git


The following commit(s) were added to refs/heads/2.x by this push:
     new 8fcedc3ce5 feature: benchmark tcc real mode (#8062)
8fcedc3ce5 is described below

commit 8fcedc3ce51c17191efb6a88af60c30127fd04c4
Author: zihenzzz <[email protected]>
AuthorDate: Tue Apr 28 13:36:37 2026 +0800

    feature: benchmark tcc real mode (#8062)
---
 changes/en-us/2.x.md                               |   1 +
 changes/zh-cn/2.x.md                               |   1 +
 test-suite/seata-benchmark-cli/README.md           |  63 +++++++++--
 test-suite/seata-benchmark-cli/pom.xml             |   5 +
 .../apache/seata/benchmark/BenchmarkRunner.java    |   3 +-
 .../seata/benchmark/executor/TCCModeExecutor.java  | 116 +++++++++++++++++++--
 .../seata/benchmark/tcc/BenchmarkTccAction.java    |  45 ++++++++
 .../benchmark/tcc/BenchmarkTccActionImpl.java      |  44 ++++++++
 8 files changed, 256 insertions(+), 22 deletions(-)

diff --git a/changes/en-us/2.x.md b/changes/en-us/2.x.md
index 2c81a635bb..5340332485 100644
--- a/changes/en-us/2.x.md
+++ b/changes/en-us/2.x.md
@@ -19,6 +19,7 @@ Add changes here for all PR submitted to the 2.x branch.
 <!-- Please add the `changes` to the following 
location(feature/bugfix/optimize/test) based on the type of PR -->
 
 ### feature:
+- [[#8062](https://github.com/apache/incubator-seata/pull/8062)] implement 
real TCC mode in benchmark CLI
 - [[#8052](https://github.com/apache/incubator-seata/pull/8052)] add 
SAGA_ANNOTATION mode to benchmark CLI
 - [[#8014](https://github.com/apache/incubator-seata/pull/8014)] add P99.9 
latency percentile to benchmark CLI
 - [[#7882](https://github.com/apache/incubator-seata/pull/7882)] add metrics 
for NamingServer
diff --git a/changes/zh-cn/2.x.md b/changes/zh-cn/2.x.md
index 3a9f53f262..95f1bc729a 100644
--- a/changes/zh-cn/2.x.md
+++ b/changes/zh-cn/2.x.md
@@ -20,6 +20,7 @@
 
 ### feature:
 
+- [[#8062](https://github.com/apache/incubator-seata/pull/8062)] 为benchmark 
CLI实现真实TCC模式(try/confirm/cancel)
 - [[#8052](https://github.com/apache/incubator-seata/pull/8052)] 为benchmark 
CLI新增SAGA_ANNOTATION模式
 - [[#7882](https://github.com/apache/incubator-seata/pull/7882)] 
为NamingServer增加Metrics监控
 - [[#7760](https://github.com/apache/incubator-seata/pull/7760)] 
统一Jackson/fastjson序列化器
diff --git a/test-suite/seata-benchmark-cli/README.md 
b/test-suite/seata-benchmark-cli/README.md
index 2e6d0b1180..2caedcd89f 100644
--- a/test-suite/seata-benchmark-cli/README.md
+++ b/test-suite/seata-benchmark-cli/README.md
@@ -64,21 +64,23 @@ java -jar seata-benchmark-cli.jar \
   --server 127.0.0.1:8091 \
   --mode AT \
   --tps 100 \
+  --threads 1 \
   --duration 60
 
-# TCC mode benchmark
+# TCC mode benchmark (empty transaction)
 java -jar seata-benchmark-cli.jar \
   --server 127.0.0.1:8091 \
   --mode TCC \
-  --tps 200 \
-  --threads 20 \
-  --duration 120
+  --tps 100 \
+  --threads 1 \
+  --duration 60
 
 # SAGA mode benchmark (empty transaction)
 java -jar seata-benchmark-cli.jar \
   --server 127.0.0.1:8091 \
   --mode SAGA \
   --tps 100 \
+  --threads 1 \
   --duration 60
 
 # SAGA_ANNOTATION mode benchmark (empty transaction)
@@ -86,6 +88,7 @@ java -jar seata-benchmark-cli.jar \
   --server 127.0.0.1:8091 \
   --mode SAGA_ANNOTATION \
   --tps 100 \
+  --threads 1 \
   --duration 60
 ```
 
@@ -97,6 +100,16 @@ java -jar seata-benchmark-cli.jar \
   --server 127.0.0.1:8091 \
   --mode AT \
   --tps 100 \
+  --threads 1 \
+  --duration 60 \
+  --branches 3
+
+# TCC mode with real try/confirm/cancel
+java -jar seata-benchmark-cli.jar \
+  --server 127.0.0.1:8091 \
+  --mode TCC \
+  --tps 100 \
+  --threads 1 \
   --duration 60 \
   --branches 3
 
@@ -105,6 +118,7 @@ java -jar seata-benchmark-cli.jar \
   --server 127.0.0.1:8091 \
   --mode SAGA \
   --tps 100 \
+  --threads 1 \
   --duration 60 \
   --branches 3 \
   --rollback-percentage 5
@@ -114,6 +128,7 @@ java -jar seata-benchmark-cli.jar \
   --server 127.0.0.1:8091 \
   --mode SAGA \
   --tps 100 \
+  --threads 1 \
   --duration 60 \
   --branches 3 \
   --saga-shape order
@@ -123,6 +138,7 @@ java -jar seata-benchmark-cli.jar \
   --server 127.0.0.1:8091 \
   --mode SAGA \
   --tps 100 \
+  --threads 1 \
   --duration 60 \
   --branches 3 \
   --saga-shape order \
@@ -133,6 +149,7 @@ java -jar seata-benchmark-cli.jar \
   --server 127.0.0.1:8091 \
   --mode SAGA \
   --tps 100 \
+  --threads 1 \
   --duration 60 \
   --branches 3 \
   --rollback-percentage 20 \
@@ -506,15 +523,34 @@ java -jar seata-benchmark-cli.jar --server 127.0.0.1:8091 
\
   --mode SAGA_ANNOTATION --tps 10000 --threads 50 --duration 60 --branches 3
 ```
 
-### Test TCC Mode at High Load
+### Test TCC Mode (try/confirm/cancel)
 
 ```bash
+# Empty mode: protocol overhead only (fixed TPS)
 java -jar seata-benchmark-cli.jar \
   --server 127.0.0.1:8091 \
   --mode TCC \
-  --tps 500 \
+  --tps 100 \
+  --threads 1 \
+  --duration 60
+
+# Empty mode: max throughput (fixed concurrency)
+java -jar seata-benchmark-cli.jar \
+  --server 127.0.0.1:8091 \
+  --mode TCC \
+  --tps 100000 \
   --threads 50 \
-  --duration 300
+  --duration 60
+
+# Real mode: 3 branches per transaction, 10% cancel rate
+java -jar seata-benchmark-cli.jar \
+  --server 127.0.0.1:8091 \
+  --mode TCC \
+  --tps 100 \
+  --threads 1 \
+  --duration 60 \
+  --branches 3 \
+  --rollback-percentage 10
 ```
 
 ### Test with Warmup
@@ -524,6 +560,7 @@ java -jar seata-benchmark-cli.jar \
   --server 127.0.0.1:8091 \
   --mode AT \
   --tps 200 \
+  --threads 1 \
   --duration 120 \
   --warmup-duration 30
 ```
@@ -535,7 +572,7 @@ java -jar seata-benchmark-cli.jar \
 | Mode             | Empty Mode (branches=0) | Real Mode (branches>0) |
 |------------------|-------------------------|------------------------|
 | AT               | Pure protocol overhead  | MySQL via Testcontainers 
(account transfer) |
-| TCC              | Mock implementation     | Mock implementation |
+| TCC              | Pure protocol overhead  | Real try/confirm/cancel via 
@LocalTCC interceptor |
 | SAGA             | Mock simulation         | State machine engine with 
compensation |
 | SAGA_ANNOTATION  | Pure protocol overhead  | Annotation interceptor + TC 
compensation callback |
 
@@ -544,7 +581,7 @@ java -jar seata-benchmark-cli.jar \
 For accurate benchmarking of Seata Server capacity, the tool executes **empty 
transactions**:
 
 - **AT Mode**: Only `begin()` and `commit()` operations, no SQL execution
-- **TCC Mode**: Empty transaction flow (mock implementation)
+- **TCC Mode**: Empty global transaction, no branch registration
 - **SAGA Mode**: Simplified simulation without state machine
 - **SAGA_ANNOTATION Mode**: Empty global transaction, no branch registration
 
@@ -564,6 +601,13 @@ When `--branches` is set to a value greater than 0:
   - Executes real account transfer operations
   - Each branch performs debit/credit operations
 
+- **TCC Mode**:
+  - Uses `@LocalTCC` + `@TwoPhaseBusinessAction` annotation path
+  - Each branch is registered via the TCC interceptor (JDK dynamic proxy, no 
Spring required)
+  - `try` (prepare) runs in the business thread; `commit` / `rollback` are 
invoked by the TC
+  - No-op implementation so the benchmark measures pure TCC protocol overhead
+  - `--branches N` = N TCC branch registrations per transaction
+
 - **SAGA Mode**:
   - Uses Seata state machine engine
   - Executes predefined state machine definitions
@@ -675,7 +719,6 @@ Logs are written to `seata-benchmark.log` in the current 
directory.
 
 **v1.1 - Enhancement:**
 - P99.9 percentile
-- Real TCC implementation with try/confirm/cancel
 - XA mode support
 
 **v2.0 - Advanced Features:**
diff --git a/test-suite/seata-benchmark-cli/pom.xml 
b/test-suite/seata-benchmark-cli/pom.xml
index 774145c0d6..410eea45a7 100644
--- a/test-suite/seata-benchmark-cli/pom.xml
+++ b/test-suite/seata-benchmark-cli/pom.xml
@@ -46,6 +46,11 @@
             <artifactId>seata-tm</artifactId>
             <version>${project.version}</version>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>seata-tcc</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>seata-saga-annotation</artifactId>
diff --git 
a/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/BenchmarkRunner.java
 
b/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/BenchmarkRunner.java
index 3e5d00ec21..0fda84659c 100644
--- 
a/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/BenchmarkRunner.java
+++ 
b/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/BenchmarkRunner.java
@@ -127,7 +127,8 @@ public class BenchmarkRunner {
                 System.out.println("Creating AT mode executor" + atMode + 
"\n");
                 return new ATModeExecutor(config);
             case TCC:
-                System.out.println("Creating TCC mode executor (mock 
implementation)\n");
+                String tccMode = isRealMode ? " (try/confirm/cancel)" : " 
(empty transaction)";
+                System.out.println("Creating TCC mode executor" + tccMode + 
"\n");
                 return new TCCModeExecutor(config);
             case SAGA:
                 String sagaMode = isRealMode ? " (state machine engine)" : " 
(empty transaction)";
diff --git 
a/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/executor/TCCModeExecutor.java
 
b/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/executor/TCCModeExecutor.java
index b9cb993b21..76fb140cb1 100644
--- 
a/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/executor/TCCModeExecutor.java
+++ 
b/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/executor/TCCModeExecutor.java
@@ -17,41 +17,133 @@
 package org.apache.seata.benchmark.executor;
 
 import org.apache.seata.benchmark.config.BenchmarkConfig;
+import org.apache.seata.benchmark.tcc.BenchmarkTccAction;
+import org.apache.seata.benchmark.tcc.BenchmarkTccActionImpl;
+import org.apache.seata.integration.tx.api.interceptor.InvocationWrapper;
+import 
org.apache.seata.integration.tx.api.interceptor.handler.ProxyInvocationHandler;
+import org.apache.seata.rm.tcc.interceptor.parser.TccActionInterceptorParser;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import java.lang.reflect.Method;
+import java.lang.reflect.Proxy;
+
 /**
- * TCC mode transaction executor (simplified mock implementation)
- * Note: For Phase 1 (MVP), TCC mode executes empty transactions similar to AT 
mode.
- * Full TCC implementation with try/confirm/cancel will be added in future 
versions.
+ * TCC mode transaction executor.
+ *
+ * <p>Supports two sub-modes controlled by {@code --branches}:
+ * <ul>
+ *   <li><b>Empty mode</b> ({@code branches == 0}): starts and commits an 
empty global
+ *       transaction. Measures pure Seata protocol overhead with no branch 
registration.</li>
+ *   <li><b>Real mode</b> ({@code branches > 0}): registers {@code branches} 
TCC branches
+ *       per transaction via the {@link BenchmarkTccAction} proxy. On commit 
the TC invokes
+ *       {@link BenchmarkTccAction#commit} for every registered branch; on 
rollback it invokes
+ *       {@link BenchmarkTccAction#rollback}.</li>
+ * </ul>
+ *
+ * <p>No Spring container is required. A JDK dynamic proxy wraps
+ * {@link org.apache.seata.rm.tcc.interceptor.TccActionInterceptorHandler},
+ * which is equivalent to what Spring AOP would produce at runtime.
  */
 public class TCCModeExecutor extends AbstractTransactionExecutor {
 
     private static final Logger LOGGER = 
LoggerFactory.getLogger(TCCModeExecutor.class);
 
+    private BenchmarkTccAction actionProxy;
+    private BenchmarkTccActionImpl actionImpl;
+
     public TCCModeExecutor(BenchmarkConfig config) {
         super(config);
     }
 
+    private boolean isRealMode() {
+        return config.getBranches() > 0;
+    }
+
     @Override
     public void init() {
-        LOGGER.info("TCC mode executor initialized (simplified mock mode)");
+        if (isRealMode()) {
+            initRealMode();
+        } else {
+            LOGGER.info("TCC mode executor initialized (empty transaction 
mode)");
+        }
+    }
+
+    private void initRealMode() {
+        LOGGER.info("Initializing TCC mode executor (try/confirm/cancel)");
+
+        actionImpl = new BenchmarkTccActionImpl();
+
+        // TccActionInterceptorParser does two things:
+        // 1. Registers TCCResource with DefaultResourceManager (enables TC 
callbacks)
+        // 2. Returns a TccActionInterceptorHandler for proxy dispatch
+        TccActionInterceptorParser parser = new TccActionInterceptorParser();
+        ProxyInvocationHandler handler;
+        try {
+            handler = parser.parserInterfaceToProxy(actionImpl, 
"benchmarkTccService");
+        } catch (Exception e) {
+            throw new RuntimeException("Failed to initialize TCC proxy", e);
+        }
+        if (handler == null) {
+            throw new IllegalStateException(
+                    "Failed to initialize TCC proxy: no 
@TwoPhaseBusinessAction method was found for "
+                            + BenchmarkTccAction.class.getName());
+        }
+
+        // Wrap the handler with a JDK dynamic proxy — equivalent to Spring 
AOP proxy
+        actionProxy = (BenchmarkTccAction) Proxy.newProxyInstance(
+                BenchmarkTccAction.class.getClassLoader(),
+                new Class[] {BenchmarkTccAction.class},
+                (proxy, method, args) -> handler.invoke(new 
InvocationWrapper() {
+                    @Override
+                    public Method getMethod() {
+                        return method;
+                    }
+
+                    @Override
+                    public Object getProxy() {
+                        return proxy;
+                    }
+
+                    @Override
+                    public Object getTarget() {
+                        return actionImpl;
+                    }
+
+                    @Override
+                    public Object[] getArguments() {
+                        return args;
+                    }
+
+                    @Override
+                    public Object proceed() throws Throwable {
+                        return method.invoke(actionImpl, args);
+                    }
+                }));
+
+        LOGGER.info("TCC mode executor initialized ({} branches per 
transaction)", config.getBranches());
     }
 
     @Override
-    protected String getTransactionName() {
-        return "benchmark-tcc-tx";
+    protected void executeBusinessLogic() throws Exception {
+        if (!isRealMode()) {
+            return;
+        }
+        // Each proxy call triggers the TCC interceptor which registers
+        // one TCC branch with the TC via branchRegister RPC.
+        for (int i = 0; i < config.getBranches(); i++) {
+            actionProxy.prepare(null);
+        }
     }
 
     @Override
-    protected int getBranchCount() {
-        return 0;
+    protected String getTransactionName() {
+        return "benchmark-tcc-tx";
     }
 
     @Override
-    protected void executeBusinessLogic() throws Exception {
-        // Empty transaction - no TCC operations
-        // Full TCC with try/confirm/cancel will be implemented in future 
versions
+    protected int getBranchCount() {
+        return config.getBranches();
     }
 
     @Override
@@ -61,6 +153,8 @@ public class TCCModeExecutor extends 
AbstractTransactionExecutor {
 
     @Override
     public void destroy() {
+        actionProxy = null;
+        actionImpl = null;
         LOGGER.info("TCC mode executor destroyed");
     }
 }
diff --git 
a/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/tcc/BenchmarkTccAction.java
 
b/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/tcc/BenchmarkTccAction.java
new file mode 100644
index 0000000000..6aec9445fb
--- /dev/null
+++ 
b/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/tcc/BenchmarkTccAction.java
@@ -0,0 +1,45 @@
+/*
+ * 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.seata.benchmark.tcc;
+
+import org.apache.seata.rm.tcc.api.BusinessActionContext;
+import org.apache.seata.rm.tcc.api.LocalTCC;
+import org.apache.seata.rm.tcc.api.TwoPhaseBusinessAction;
+
+/**
+ * Benchmark TCC action interface.
+ *
+ * <p>Used by {@link org.apache.seata.benchmark.executor.TCCModeExecutor} in 
real mode
+ * ({@code branches > 0}) to drive the TCC protocol path through the Seata 
interceptor.
+ * Each call to {@link #prepare} registers one TCC branch with the TC. On 
global commit
+ * the TC invokes {@link #commit}; on global rollback it invokes {@link 
#rollback}.
+ *
+ * <p>All three methods are intentionally no-ops so the benchmark measures 
only Seata
+ * protocol overhead, not business logic.
+ */
+@LocalTCC
+public interface BenchmarkTccAction {
+
+    String ACTION_NAME = "seata-benchmark-cli-benchmarkTccAction";
+
+    @TwoPhaseBusinessAction(name = ACTION_NAME, commitMethod = "commit", 
rollbackMethod = "rollback")
+    boolean prepare(BusinessActionContext context);
+
+    boolean commit(BusinessActionContext context);
+
+    boolean rollback(BusinessActionContext context);
+}
diff --git 
a/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/tcc/BenchmarkTccActionImpl.java
 
b/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/tcc/BenchmarkTccActionImpl.java
new file mode 100644
index 0000000000..6db6a0c120
--- /dev/null
+++ 
b/test-suite/seata-benchmark-cli/src/main/java/org/apache/seata/benchmark/tcc/BenchmarkTccActionImpl.java
@@ -0,0 +1,44 @@
+/*
+ * 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.seata.benchmark.tcc;
+
+import org.apache.seata.rm.tcc.api.BusinessActionContext;
+
+/**
+ * No-op implementation of {@link BenchmarkTccAction}.
+ *
+ * <p>All three TCC phases return immediately so the benchmark measures only 
the
+ * Seata TCC protocol overhead (branch registration and TC callbacks), not any
+ * business logic execution time.
+ */
+public class BenchmarkTccActionImpl implements BenchmarkTccAction {
+
+    @Override
+    public boolean prepare(BusinessActionContext context) {
+        return true;
+    }
+
+    @Override
+    public boolean commit(BusinessActionContext context) {
+        return true;
+    }
+
+    @Override
+    public boolean rollback(BusinessActionContext context) {
+        return true;
+    }
+}


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to