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 b3b30ae6cac Stop data region write retry promptly (#18730) (#18774)
b3b30ae6cac is described below

commit b3b30ae6cacf66222c9bb22c93a547a0c75c1c24
Author: Caideyipi <[email protected]>
AuthorDate: Wed Sep 30 15:44:53 2026 +0800

    Stop data region write retry promptly (#18730) (#18774)
---
 .../dataregion/DataRegionStateMachine.java         |   8 +-
 .../dataregion/DataRegionStateMachineTest.java     | 114 +++++++++++++++++++++
 2 files changed, 121 insertions(+), 1 deletion(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachine.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachine.java
index 9a26dba4e66..a76889d8b63 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachine.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachine.java
@@ -224,11 +224,13 @@ public class DataRegionStateMachine extends 
BaseStateMachine {
               "write operation still failed after {} retry times, because {}.",
               MAX_WRITE_RETRY_TIMES,
               result.getCode());
+          break;
         }
         try {
-          Thread.sleep(WRITE_RETRY_WAIT_TIME_IN_MS);
+          waitBeforeNextWriteRetry();
         } catch (InterruptedException e) {
           Thread.currentThread().interrupt();
+          break;
         }
       } else {
         break;
@@ -237,6 +239,10 @@ public class DataRegionStateMachine extends 
BaseStateMachine {
     return result;
   }
 
+  protected void waitBeforeNextWriteRetry() throws InterruptedException {
+    Thread.sleep(WRITE_RETRY_WAIT_TIME_IN_MS);
+  }
+
   @Override
   public DataSet read(IConsensusRequest request) {
     if (request instanceof GetConsensusReqReaderPlan) {
diff --git 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachineTest.java
 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachineTest.java
index 7a77eada418..40a769cde05 100644
--- 
a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachineTest.java
+++ 
b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/consensus/statemachine/dataregion/DataRegionStateMachineTest.java
@@ -19,18 +19,26 @@
 
 package org.apache.iotdb.db.consensus.statemachine.dataregion;
 
+import org.apache.iotdb.common.rpc.thrift.TSStatus;
 import org.apache.iotdb.commons.exception.IllegalPathException;
 import org.apache.iotdb.commons.path.PartialPath;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode;
 import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId;
+import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor;
 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.rpc.TSStatusCode;
 
 import org.apache.tsfile.enums.TSDataType;
 import org.junit.Assert;
 import org.junit.Test;
 
+import java.io.DataOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
 import java.util.ArrayList;
+import java.util.Collections;
 import java.util.List;
 
 public class DataRegionStateMachineTest {
@@ -119,4 +127,110 @@ public class DataRegionStateMachineTest {
     InsertNode mergedNode = list.get(0).mergeInsertNode(list);
     Assert.assertTrue(mergedNode instanceof InsertRowsNode);
   }
+
+  @Test
+  public void testWriteRetryDoesNotWaitAfterLastAttempt() {
+    final TestingDataRegionStateMachine stateMachine = new 
TestingDataRegionStateMachine(false);
+    final FixedStatusPlanNode planNode =
+        new 
FixedStatusPlanNode(TSStatusCode.WRITE_PROCESS_REJECT.getStatusCode());
+
+    final TSStatus status = stateMachine.write(planNode);
+
+    Assert.assertEquals(TSStatusCode.WRITE_PROCESS_REJECT.getStatusCode(), 
status.getCode());
+    Assert.assertEquals(5, planNode.getAcceptCount());
+    Assert.assertEquals(4, stateMachine.getWaitCount());
+  }
+
+  @Test
+  public void testInterruptedWriteRetryStopsImmediately() {
+    Thread.interrupted();
+    try {
+      final TestingDataRegionStateMachine stateMachine = new 
TestingDataRegionStateMachine(true);
+      final FixedStatusPlanNode planNode =
+          new 
FixedStatusPlanNode(TSStatusCode.WRITE_PROCESS_REJECT.getStatusCode());
+
+      final TSStatus status = stateMachine.write(planNode);
+
+      Assert.assertEquals(TSStatusCode.WRITE_PROCESS_REJECT.getStatusCode(), 
status.getCode());
+      Assert.assertEquals(1, planNode.getAcceptCount());
+      Assert.assertEquals(1, stateMachine.getWaitCount());
+      Assert.assertTrue(Thread.currentThread().isInterrupted());
+    } finally {
+      Thread.interrupted();
+    }
+  }
+
+  private static class TestingDataRegionStateMachine extends 
DataRegionStateMachine {
+
+    private final boolean interruptOnWait;
+    private int waitCount;
+
+    private TestingDataRegionStateMachine(final boolean interruptOnWait) {
+      super(null);
+      this.interruptOnWait = interruptOnWait;
+    }
+
+    private int getWaitCount() {
+      return waitCount;
+    }
+
+    @Override
+    protected void waitBeforeNextWriteRetry() throws InterruptedException {
+      ++waitCount;
+      if (interruptOnWait) {
+        throw new InterruptedException();
+      }
+    }
+  }
+
+  private static class FixedStatusPlanNode extends PlanNode {
+
+    private final int statusCode;
+    private int acceptCount;
+
+    private FixedStatusPlanNode(final int statusCode) {
+      super(new PlanNodeId("test"));
+      this.statusCode = statusCode;
+    }
+
+    private int getAcceptCount() {
+      return acceptCount;
+    }
+
+    @SuppressWarnings("unchecked")
+    @Override
+    public <R, C> R accept(final PlanVisitor<R, C> visitor, final C context) {
+      ++acceptCount;
+      return (R) new TSStatus(statusCode);
+    }
+
+    @Override
+    public List<PlanNode> getChildren() {
+      return Collections.emptyList();
+    }
+
+    @Override
+    public void addChild(final PlanNode child) {}
+
+    @Override
+    public PlanNode clone() {
+      return new FixedStatusPlanNode(statusCode);
+    }
+
+    @Override
+    public int allowedChildCount() {
+      return NO_CHILD_ALLOWED;
+    }
+
+    @Override
+    public List<String> getOutputColumnNames() {
+      return Collections.emptyList();
+    }
+
+    @Override
+    protected void serializeAttributes(final ByteBuffer byteBuffer) {}
+
+    @Override
+    protected void serializeAttributes(final DataOutputStream stream) throws 
IOException {}
+  }
 }

Reply via email to